summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.mk2
-rw-r--r--api/current.txt62
-rw-r--r--api/system-current.txt67
-rw-r--r--cmds/am/src/com/android/commands/am/Am.java44
-rw-r--r--cmds/svc/src/com/android/commands/svc/NfcCommand.java85
-rw-r--r--cmds/svc/src/com/android/commands/svc/Svc.java3
-rw-r--r--core/java/android/app/Activity.java18
-rw-r--r--core/java/android/app/ActivityManager.java39
-rw-r--r--core/java/android/app/ActivityManagerNative.java50
-rw-r--r--core/java/android/app/ActivityThread.java57
-rw-r--r--core/java/android/app/ActivityTransitionState.java8
-rw-r--r--core/java/android/app/ActivityView.java2
-rw-r--r--core/java/android/app/ApplicationPackageManager.java4
-rw-r--r--core/java/android/app/ApplicationThreadNative.java35
-rw-r--r--core/java/android/app/BackStackRecord.java38
-rw-r--r--core/java/android/app/Fragment.java10
-rw-r--r--core/java/android/app/FragmentController.java1
-rw-r--r--core/java/android/app/FragmentManager.java11
-rw-r--r--core/java/android/app/IActivityManager.java8
-rw-r--r--core/java/android/app/IApplicationThread.java3
-rw-r--r--core/java/android/app/Instrumentation.java2
-rw-r--r--core/java/android/app/StatusBarManager.java3
-rw-r--r--core/java/android/app/SystemServiceRegistry.java2
-rw-r--r--core/java/android/app/admin/DeviceAdminInfo.java2
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java88
-rw-r--r--core/java/android/content/Intent.java71
-rw-r--r--core/java/android/content/pm/ActivityInfo.java9
-rw-r--r--core/java/android/content/pm/PackageParser.java35
-rw-r--r--core/java/android/content/pm/UserInfo.java11
-rw-r--r--core/java/android/content/res/Configuration.java100
-rw-r--r--core/java/android/hardware/display/DisplayManagerGlobal.java8
-rw-r--r--core/java/android/hardware/display/IDisplayManager.aidl3
-rw-r--r--core/java/android/hardware/fingerprint/FingerprintManager.java5
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java55
-rw-r--r--core/java/android/net/ConnectivityManager.java6
-rw-r--r--core/java/android/net/NetworkScoreManager.java3
-rw-r--r--core/java/android/os/BatteryStats.java13
-rw-r--r--core/java/android/os/PowerManagerInternal.java11
-rw-r--r--core/java/android/os/RecoverySystem.java2
-rw-r--r--core/java/android/os/StrictMode.java2
-rw-r--r--core/java/android/os/UserHandle.java35
-rw-r--r--core/java/android/os/storage/VolumeInfo.java2
-rw-r--r--core/java/android/provider/DocumentsContract.java5
-rw-r--r--core/java/android/provider/Settings.java24
-rw-r--r--core/java/android/util/PathParser.java26
-rw-r--r--core/java/android/view/BatchedInputEventReceiver.java82
-rw-r--r--core/java/android/view/Display.java133
-rw-r--r--core/java/android/view/DisplayInfo.java52
-rw-r--r--core/java/android/view/DragEvent.java37
-rw-r--r--core/java/android/view/DropPermissionHolder.java161
-rw-r--r--core/java/android/view/IWindowManager.aidl3
-rw-r--r--core/java/android/view/ThreadedRenderer.java61
-rw-r--r--core/java/android/view/View.java115
-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.java97
-rw-r--r--core/java/android/view/Window.java26
-rw-r--r--core/java/android/view/WindowManager.java8
-rw-r--r--core/java/android/view/WindowManagerGlobal.java7
-rw-r--r--core/java/android/webkit/WebView.java3
-rw-r--r--core/java/android/widget/AbsListView.java93
-rw-r--r--core/java/android/widget/AbsSeekBar.java27
-rw-r--r--core/java/android/widget/AdapterView.java20
-rw-r--r--core/java/android/widget/DropDownListView.java5
-rw-r--r--core/java/android/widget/GridView.java2
-rw-r--r--core/java/android/widget/ListView.java2
-rw-r--r--core/java/android/widget/MenuItemHoverListener.java13
-rw-r--r--core/java/android/widget/MenuPopupWindow.java82
-rw-r--r--core/java/android/widget/PopupMenu.java21
-rw-r--r--core/java/android/widget/PopupWindow.java38
-rw-r--r--core/java/android/widget/ProgressBar.java148
-rw-r--r--core/java/android/widget/RemoteViews.java41
-rw-r--r--core/java/android/widget/Switch.java2
-rw-r--r--core/java/android/widget/TimePickerClockDelegate.java8
-rw-r--r--core/java/android/widget/Toolbar.java138
-rw-r--r--core/java/com/android/internal/app/ChooserActivity.java8
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java25
-rw-r--r--core/java/com/android/internal/inputmethod/InputMethodUtils.java18
-rw-r--r--core/java/com/android/internal/os/BatteryStatsHelper.java2
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java243
-rw-r--r--core/java/com/android/internal/os/CpuPowerCalculator.java37
-rw-r--r--core/java/com/android/internal/os/InstallerConnection.java19
-rw-r--r--core/java/com/android/internal/os/KernelCpuSpeedReader.java36
-rw-r--r--core/java/com/android/internal/os/KernelUidCpuTimeReader.java2
-rw-r--r--core/java/com/android/internal/os/PowerProfile.java82
-rw-r--r--core/java/com/android/internal/os/WrapperInit.java18
-rw-r--r--core/java/com/android/internal/os/ZygoteInit.java4
-rw-r--r--core/java/com/android/internal/policy/PhoneWindow.java102
-rw-r--r--core/java/com/android/internal/statusbar/IStatusBar.aidl4
-rw-r--r--core/java/com/android/internal/view/FloatingActionMode.java5
-rw-r--r--core/java/com/android/internal/view/IDropPermissionHolder.aidl26
-rw-r--r--core/java/com/android/internal/view/menu/CascadingMenuPopup.java264
-rw-r--r--core/java/com/android/internal/view/menu/ContextMenuBuilder.java26
-rw-r--r--core/java/com/android/internal/view/menu/MenuAdapter.java4
-rw-r--r--core/java/com/android/internal/view/menu/MenuItemImpl.java2
-rw-r--r--core/java/com/android/internal/view/menu/MenuPopup.java45
-rw-r--r--core/java/com/android/internal/view/menu/MenuPopupHelper.java98
-rw-r--r--core/java/com/android/internal/view/menu/StandardMenuPopup.java143
-rw-r--r--core/java/com/android/internal/view/menu/SubMenuBuilder.java2
-rw-r--r--core/java/com/android/internal/widget/FloatingToolbar.java5
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java14
-rw-r--r--core/java/com/android/server/LocalServices.java12
-rw-r--r--core/java/com/android/server/backup/NotificationBackupHelper.java6
-rw-r--r--core/java/com/android/server/backup/PreferredActivityBackupHelper.java14
-rw-r--r--core/java/com/android/server/backup/SystemBackupAgent.java6
-rw-r--r--core/jni/AndroidRuntime.cpp2
-rwxr-xr-xcore/jni/android/graphics/Bitmap.cpp2
-rw-r--r--core/jni/android/graphics/BitmapFactory.cpp4
-rw-r--r--core/jni/android/graphics/BitmapRegionDecoder.cpp8
-rw-r--r--core/jni/android/graphics/Camera.cpp2
-rw-r--r--core/jni/android/graphics/CanvasProperty.cpp2
-rw-r--r--core/jni/android/graphics/ColorFilter.cpp8
-rw-r--r--core/jni/android/graphics/DrawFilter.cpp4
-rw-r--r--core/jni/android/graphics/FontFamily.cpp2
-rw-r--r--core/jni/android/graphics/Interpolator.cpp2
-rw-r--r--core/jni/android/graphics/MaskFilter.cpp8
-rw-r--r--core/jni/android/graphics/Matrix.cpp2
-rw-r--r--core/jni/android/graphics/Movie.cpp2
-rw-r--r--core/jni/android/graphics/NinePatch.cpp2
-rw-r--r--core/jni/android/graphics/Paint.cpp2
-rw-r--r--core/jni/android/graphics/Path.cpp2
-rw-r--r--core/jni/android/graphics/PathEffect.cpp14
-rw-r--r--core/jni/android/graphics/PathMeasure.cpp2
-rw-r--r--core/jni/android/graphics/PorterDuff.cpp2
-rw-r--r--core/jni/android/graphics/Rasterizer.cpp4
-rw-r--r--core/jni/android/graphics/Region.cpp4
-rw-r--r--core/jni/android/graphics/Shader.cpp14
-rw-r--r--core/jni/android/graphics/SurfaceTexture.cpp9
-rw-r--r--core/jni/android/graphics/Typeface.cpp2
-rw-r--r--core/jni/android/graphics/Xfermode.cpp6
-rw-r--r--core/jni/android/graphics/YuvToJpegEncoder.cpp2
-rw-r--r--core/jni/android/graphics/pdf/PdfDocument.cpp2
-rw-r--r--core/jni/android/graphics/pdf/PdfEditor.cpp2
-rw-r--r--core/jni/android/graphics/pdf/PdfRenderer.cpp2
-rw-r--r--core/jni/android/opengl/util.cpp14
-rw-r--r--core/jni/android_animation_PropertyValuesHolder.cpp2
-rw-r--r--core/jni/android_content_res_ObbScanner.cpp2
-rw-r--r--core/jni/android_database_CursorWindow.cpp2
-rw-r--r--core/jni/android_database_SQLiteConnection.cpp2
-rw-r--r--core/jni/android_database_SQLiteDebug.cpp2
-rw-r--r--core/jni/android_database_SQLiteGlobal.cpp2
-rw-r--r--core/jni/android_ddm_DdmHandleNativeHeap.cpp2
-rw-r--r--core/jni/android_graphics_Canvas.cpp2
-rw-r--r--core/jni/android_graphics_Picture.cpp2
-rw-r--r--core/jni/android_hardware_Camera.cpp2
-rw-r--r--core/jni/android_hardware_SensorManager.cpp4
-rw-r--r--core/jni/android_hardware_SerialPort.cpp2
-rw-r--r--core/jni/android_hardware_SoundTrigger.cpp4
-rw-r--r--core/jni/android_hardware_UsbDevice.cpp2
-rw-r--r--core/jni/android_hardware_UsbDeviceConnection.cpp2
-rw-r--r--core/jni/android_hardware_UsbRequest.cpp2
-rw-r--r--core/jni/android_hardware_camera2_CameraMetadata.cpp2
-rw-r--r--core/jni/android_hardware_camera2_DngCreator.cpp2
-rw-r--r--core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp2
-rw-r--r--core/jni/android_hardware_camera2_legacy_PerfMeasurement.cpp2
-rw-r--r--core/jni/android_hardware_location_ActivityRecognitionHardware.cpp2
-rw-r--r--core/jni/android_media_AudioRecord.cpp2
-rw-r--r--core/jni/android_media_AudioSystem.cpp4
-rw-r--r--core/jni/android_media_AudioTrack.cpp2
-rw-r--r--core/jni/android_media_JetPlayer.cpp2
-rw-r--r--core/jni/android_media_RemoteDisplay.cpp2
-rw-r--r--core/jni/android_media_ToneGenerator.cpp2
-rw-r--r--core/jni/android_net_LocalSocketImpl.cpp2
-rw-r--r--core/jni/android_net_NetUtils.cpp2
-rw-r--r--core/jni/android_net_TrafficStats.cpp2
-rw-r--r--core/jni/android_opengl_EGL14.cpp2
-rw-r--r--core/jni/android_opengl_EGLExt.cpp2
-rw-r--r--core/jni/android_opengl_GLES10.cpp2
-rw-r--r--core/jni/android_opengl_GLES10Ext.cpp2
-rw-r--r--core/jni/android_opengl_GLES11.cpp2
-rw-r--r--core/jni/android_opengl_GLES11Ext.cpp2
-rw-r--r--core/jni/android_opengl_GLES20.cpp2
-rw-r--r--core/jni/android_opengl_GLES30.cpp2
-rw-r--r--core/jni/android_opengl_GLES31.cpp2
-rw-r--r--core/jni/android_opengl_GLES31Ext.cpp2
-rw-r--r--core/jni/android_os_Debug.cpp2
-rw-r--r--core/jni/android_os_MessageQueue.cpp2
-rw-r--r--core/jni/android_os_SELinux.cpp2
-rw-r--r--core/jni/android_os_SystemClock.cpp2
-rw-r--r--core/jni/android_os_SystemProperties.cpp2
-rw-r--r--core/jni/android_os_Trace.cpp2
-rw-r--r--core/jni/android_os_UEventObserver.cpp2
-rw-r--r--core/jni/android_server_NetworkManagementSocketTagger.cpp2
-rw-r--r--core/jni/android_text_AndroidBidi.cpp2
-rw-r--r--core/jni/android_text_AndroidCharacter.cpp2
-rw-r--r--core/jni/android_text_StaticLayout.cpp2
-rw-r--r--core/jni/android_util_AssetManager.cpp2
-rw-r--r--core/jni/android_util_EventLog.cpp2
-rw-r--r--core/jni/android_util_FileObserver.cpp2
-rw-r--r--core/jni/android_util_Log.cpp2
-rw-r--r--core/jni/android_util_StringBlock.cpp2
-rw-r--r--core/jni/android_util_XmlBlock.cpp2
-rw-r--r--core/jni/android_view_DisplayEventReceiver.cpp2
-rw-r--r--core/jni/android_view_GraphicBuffer.cpp2
-rw-r--r--core/jni/android_view_HardwareLayer.cpp2
-rw-r--r--core/jni/android_view_InputChannel.cpp2
-rw-r--r--core/jni/android_view_InputEventReceiver.cpp2
-rw-r--r--core/jni/android_view_InputEventSender.cpp2
-rw-r--r--core/jni/android_view_KeyCharacterMap.cpp2
-rw-r--r--core/jni/android_view_MotionEvent.cpp2
-rw-r--r--core/jni/android_view_RenderNode.cpp2
-rw-r--r--core/jni/android_view_RenderNodeAnimator.cpp2
-rw-r--r--core/jni/android_view_Surface.cpp2
-rw-r--r--core/jni/android_view_SurfaceControl.cpp2
-rw-r--r--core/jni/android_view_SurfaceSession.cpp2
-rw-r--r--core/jni/android_view_TextureView.cpp2
-rw-r--r--core/jni/android_view_ThreadedRenderer.cpp34
-rw-r--r--core/jni/android_view_VelocityTracker.cpp2
-rw-r--r--core/jni/com_android_internal_content_NativeLibraryHelper.cpp2
-rw-r--r--core/jni/com_android_internal_net_NetworkStatsFactory.cpp2
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp2
-rw-r--r--core/jni/com_android_internal_util_VirtualRefBasePtr.cpp2
-rw-r--r--core/jni/com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp2
-rw-r--r--core/jni/com_google_android_gles_jni_EGLImpl.cpp2
-rw-r--r--core/jni/com_google_android_gles_jni_GLImpl.cpp2
-rw-r--r--core/res/AndroidManifest.xml10
-rw-r--r--core/res/res/color/btn_colored_background_material.xml (renamed from core/res/res/color/btn_colored_material.xml)3
-rw-r--r--core/res/res/color/btn_colored_borderless_text_material.xml (renamed from packages/DocumentsUI/res/layout/item_loading_grid.xml)22
-rw-r--r--core/res/res/color/btn_colored_text_material.xml3
-rw-r--r--core/res/res/drawable/btn_colored_material.xml2
-rw-r--r--core/res/res/layout-land/time_picker_material.xml25
-rw-r--r--core/res/res/layout/docked_stack_divider.xml (renamed from packages/DocumentsUI/res/layout/item_loading_list.xml)18
-rw-r--r--core/res/res/layout/number_picker_material.xml2
-rw-r--r--core/res/res/layout/popup_menu_header_item_layout.xml35
-rw-r--r--core/res/res/layout/time_picker_header_material.xml6
-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-mcc240-mnc01/config.xml27
-rw-r--r--core/res/res/values-mcc240-mnc05/config.xml27
-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.xml4
-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.xml30
-rw-r--r--core/res/res/values/config.xml29
-rw-r--r--core/res/res/values/dimens.xml3
-rw-r--r--core/res/res/values/dimens_material.xml1
-rw-r--r--core/res/res/values/public.xml17
-rw-r--r--core/res/res/values/styles.xml2
-rw-r--r--core/res/res/values/styles_material.xml12
-rw-r--r--core/res/res/values/styles_micro.xml1
-rw-r--r--core/res/res/values/symbols.xml6
-rw-r--r--core/res/res/values/themes_material.xml4
-rw-r--r--core/res/res/xml/power_profile.xml35
-rw-r--r--core/tests/BTtraffic/Android.mk16
-rw-r--r--core/tests/BTtraffic/AndroidManifest.xml22
-rw-r--r--core/tests/BTtraffic/README45
-rw-r--r--core/tests/BTtraffic/res/values/strings.xml3
-rw-r--r--core/tests/BTtraffic/src/com/android/google/experimental/bttraffic/BTtraffic.java328
-rw-r--r--core/tests/SvcMonitor/Android.mk16
-rw-r--r--core/tests/SvcMonitor/AndroidManifest.xml21
-rw-r--r--core/tests/SvcMonitor/README27
-rw-r--r--core/tests/SvcMonitor/res/values/strings.xml3
-rw-r--r--core/tests/SvcMonitor/src/com/android/google/experimental/svcmoniter/SvcMonitor.java209
-rw-r--r--core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp2
-rw-r--r--core/tests/coretests/assets/fonts/HintedAdvanceWidthTest-Regular.ttfbin0 -> 1136 bytes
-rw-r--r--core/tests/coretests/assets/fonts/HintedAdvanceWidthTest-Regular.ttx328
-rw-r--r--core/tests/coretests/src/android/content/pm/PackageManagerTests.java14
-rw-r--r--core/tests/coretests/src/android/graphics/PaintTest.java97
-rw-r--r--core/tests/coretests/src/android/text/method/WordIteratorTest.java458
-rw-r--r--core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java81
-rw-r--r--core/tests/coretests/src/android/widget/TextViewActivityTest.java43
-rw-r--r--core/tests/coretests/src/android/widget/TextViewWordLimitsTest.java288
-rw-r--r--core/tests/coretests/src/android/widget/espresso/DragOnTextViewActions.java281
-rw-r--r--core/tests/coretests/src/android/widget/espresso/TextViewActions.java146
-rw-r--r--core/tests/coretests/src/android/widget/espresso/TextViewAssertions.java98
-rw-r--r--core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java116
-rw-r--r--core/tests/hosttests/test-apps/SharedUid/32/jni/native.cpp4
-rw-r--r--core/tests/hosttests/test-apps/SharedUid/64/jni/native.cpp4
-rw-r--r--core/tests/hosttests/test-apps/SharedUid/dual/jni/native.cpp4
-rw-r--r--docs/html/guide/topics/renderscript/reference/rs_for_each.jd2
-rw-r--r--docs/html/guide/topics/renderscript/reference/rs_graphics.jd46
-rw-r--r--docs/html/guide/topics/renderscript/reference/rs_object_types.jd20
-rw-r--r--docs/html/guide/topics/renderscript/reference/rs_time.jd4
-rw-r--r--docs/html/guide/topics/renderscript/reference/rs_value_types.jd24
-rw-r--r--docs/html/training/location/geofencing.jd4
-rw-r--r--drm/jni/android_drm_DrmManagerClient.cpp2
-rw-r--r--graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java2
-rw-r--r--graphics/java/android/graphics/drawable/ClipDrawable.java22
-rw-r--r--graphics/java/android/graphics/drawable/Drawable.java147
-rw-r--r--graphics/java/android/graphics/drawable/DrawableContainer.java25
-rw-r--r--graphics/java/android/graphics/drawable/DrawableWrapper.java4
-rw-r--r--graphics/java/android/graphics/drawable/GradientDrawable.java14
-rw-r--r--graphics/java/android/graphics/drawable/LayerDrawable.java4
-rw-r--r--graphics/java/android/graphics/drawable/LevelListDrawable.java11
-rw-r--r--graphics/java/android/graphics/drawable/RotateDrawable.java4
-rw-r--r--graphics/java/android/graphics/drawable/ScaleDrawable.java61
-rw-r--r--graphics/java/android/graphics/drawable/VectorDrawable.java181
-rw-r--r--libs/hwui/Android.mk4
-rw-r--r--libs/hwui/Caches.cpp41
-rw-r--r--libs/hwui/Caches.h7
-rw-r--r--libs/hwui/Debug.h3
-rw-r--r--libs/hwui/DeferredDisplayList.cpp2
-rw-r--r--libs/hwui/DisplayListOp.h4
-rw-r--r--libs/hwui/Extensions.cpp66
-rw-r--r--libs/hwui/Extensions.h10
-rw-r--r--libs/hwui/FontRenderer.cpp32
-rw-r--r--libs/hwui/FontRenderer.h6
-rw-r--r--libs/hwui/GammaFontRenderer.cpp213
-rw-r--r--libs/hwui/GammaFontRenderer.h159
-rw-r--r--libs/hwui/GlopBuilder.cpp2
-rw-r--r--libs/hwui/OpenGLRenderer.cpp6
-rw-r--r--libs/hwui/PathCache.cpp4
-rw-r--r--libs/hwui/Program.h17
-rw-r--r--libs/hwui/ProgramCache.cpp48
-rw-r--r--libs/hwui/Properties.cpp13
-rw-r--r--libs/hwui/Properties.h28
-rw-r--r--libs/hwui/TessellationCache.cpp4
-rw-r--r--libs/hwui/TextureCache.cpp137
-rw-r--r--libs/hwui/TextureCache.h12
-rw-r--r--libs/hwui/TreeInfo.h2
-rw-r--r--libs/hwui/renderstate/Blend.cpp21
-rw-r--r--libs/hwui/renderstate/Blend.h3
-rw-r--r--libs/hwui/renderstate/TextureState.cpp136
-rw-r--r--libs/hwui/renderstate/TextureState.h12
-rw-r--r--libs/hwui/renderthread/CanvasContext.cpp115
-rw-r--r--libs/hwui/renderthread/CanvasContext.h24
-rw-r--r--libs/hwui/renderthread/DrawFrameTask.cpp6
-rw-r--r--libs/hwui/renderthread/DrawFrameTask.h3
-rw-r--r--libs/hwui/renderthread/EglManager.cpp10
-rw-r--r--libs/hwui/renderthread/RenderProxy.cpp62
-rw-r--r--libs/hwui/renderthread/RenderProxy.h5
-rw-r--r--libs/hwui/unit_tests/StringUtilsTests.cpp41
-rw-r--r--libs/hwui/utils/StringUtils.cpp40
-rw-r--r--libs/hwui/utils/StringUtils.h36
-rw-r--r--media/java/android/media/midi/MidiManager.java7
-rw-r--r--media/jni/android_media_AmrInputStream.cpp2
-rw-r--r--media/jni/android_media_ImageReader.cpp4
-rw-r--r--media/jni/android_media_MediaCodec.cpp2
-rw-r--r--media/jni/android_media_MediaCodecList.cpp2
-rw-r--r--media/jni/android_media_MediaCrypto.cpp2
-rw-r--r--media/jni/android_media_MediaDrm.cpp2
-rw-r--r--media/jni/android_media_MediaExtractor.cpp2
-rw-r--r--media/jni/android_media_MediaHTTPConnection.cpp2
-rw-r--r--media/jni/android_media_MediaMetadataRetriever.cpp2
-rw-r--r--media/jni/android_media_MediaMuxer.cpp2
-rw-r--r--media/jni/android_media_MediaPlayer.cpp2
-rw-r--r--media/jni/android_media_MediaProfiles.cpp8
-rw-r--r--media/jni/android_media_MediaRecorder.cpp2
-rw-r--r--media/jni/android_media_MediaScanner.cpp2
-rw-r--r--media/jni/android_media_ResampleInputStream.cpp2
-rw-r--r--media/jni/android_mtp_MtpDatabase.cpp4
-rw-r--r--media/jni/android_mtp_MtpDevice.cpp2
-rw-r--r--media/jni/android_mtp_MtpServer.cpp2
-rw-r--r--media/jni/audioeffect/android_media_AudioEffect.cpp2
-rw-r--r--media/jni/audioeffect/android_media_Visualizer.cpp2
-rw-r--r--media/jni/soundpool/SoundPool.cpp3
-rw-r--r--media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java10
-rw-r--r--packages/BackupRestoreConfirmation/res/values-ro/strings.xml4
-rw-r--r--packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java3
-rw-r--r--packages/DocumentsUI/AndroidManifest.xml26
-rw-r--r--packages/DocumentsUI/res/color/item_doc_grid_overlay.xml3
-rw-r--r--packages/DocumentsUI/res/drawable/progress_indeterminate_horizontal_material_trimmed.xml28
-rw-r--r--packages/DocumentsUI/res/drawable/vector_drawable_progress_indeterminate_horizontal_trimmed.xml53
-rw-r--r--packages/DocumentsUI/res/layout/directory_cluster.xml7
-rw-r--r--packages/DocumentsUI/res/layout/fragment_directory.xml81
-rw-r--r--packages/DocumentsUI/res/layout/fragment_message_bar.xml100
-rw-r--r--packages/DocumentsUI/res/layout/item_message_grid.xml51
-rw-r--r--packages/DocumentsUI/res/layout/item_message_list.xml54
-rw-r--r--packages/DocumentsUI/res/menu/activity.xml8
-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/attrs.xml20
-rw-r--r--packages/DocumentsUI/res/values/colors.xml10
-rw-r--r--packages/DocumentsUI/res/values/strings.xml7
-rw-r--r--packages/DocumentsUI/res/values/styles.xml25
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java163
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/CopyService.java2
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java285
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java11
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/DirectoryView.java4
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java86
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java101
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/IconUtils.java2
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/LauncherActivity.java93
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/ManageRootActivity.java10
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/MessageBar.java129
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java74
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/PickFragment.java11
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java5
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java6
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java118
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java1
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/RootsCache.java32
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java1
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/RootsLoader.java1
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/Shared.java2
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/SortingCursorWrapper.java6
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/State.java153
-rw-r--r--packages/DocumentsUI/tests/src/com/android/documentsui/DirectoryFragmentModelTest.java17
-rw-r--r--packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java1
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java7
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java61
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java6
-rw-r--r--packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java19
-rw-r--r--packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java62
-rw-r--r--packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java94
-rw-r--r--packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java2
-rw-r--r--packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java22
-rw-r--r--packages/PrintSpooler/jni/com_android_printspooler_util_BitmapSerializeUtils.cpp2
-rw-r--r--packages/PrintSpooler/res/values-uz-rUZ/strings.xml2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/TetherUtil.java12
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java2
-rw-r--r--packages/SystemUI/AndroidManifest.xml3
-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/layout/recents.xml6
-rw-r--r--packages/SystemUI/res/layout/recents_debug_overlay.xml35
-rw-r--r--packages/SystemUI/res/values-ca/strings.xml8
-rw-r--r--packages/SystemUI/res/values-da/strings.xml14
-rw-r--r--packages/SystemUI/res/values-en/donottranslate.xml23
-rw-r--r--packages/SystemUI/res/values-fa/strings.xml2
-rw-r--r--packages/SystemUI/res/values-it/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ja/strings.xml6
-rw-r--r--packages/SystemUI/res/values-land/config.xml4
-rw-r--r--packages/SystemUI/res/values-land/dimens.xml19
-rw-r--r--packages/SystemUI/res/values-sw600dp-land/dimens.xml2
-rw-r--r--packages/SystemUI/res/values-sw600dp/dimens.xml4
-rw-r--r--packages/SystemUI/res/values-sw720dp/config.xml14
-rw-r--r--packages/SystemUI/res/values-sw720dp/dimens.xml33
-rw-r--r--packages/SystemUI/res/values-uz-rUZ/strings.xml4
-rw-r--r--packages/SystemUI/res/values/colors.xml3
-rw-r--r--packages/SystemUI/res/values/config.xml16
-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
-rw-r--r--packages/SystemUI/src/com/android/systemui/RecentsComponent.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/SwipeHelper.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemUIApplication.java69
-rw-r--r--packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java (renamed from packages/SystemUI/src/com/android/systemui/analytics/LockedPhoneAnalytics.java)123
-rw-r--r--packages/SystemUI/src/com/android/systemui/analytics/SensorLoggerSession.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/AccelerationClassifier.java94
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceClassifier.java140
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceEvaluator.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/Classifier.java51
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/ClassifierData.java85
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/DistanceRatioEvaluator.java29
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/DurationCountClassifier.java31
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/DurationCountEvaluator.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/EndPointLengthClassifier.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/EndPointLengthEvaluator.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/EndPointRatioClassifier.java36
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/EndPointRatioEvaluator.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java299
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/GestureClassifier.java32
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/HistoryEvaluator.java112
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java202
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/LengthCountClassifier.java31
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/LengthCountEvaluator.java33
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/Point.java83
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java48
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/PointerCountEvaluator.java (renamed from packages/SystemUI/res/values-sw600dp-port/dimens.xml)24
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java93
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/ProximityEvaluator.java29
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/SpeedClassifier.java37
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/SpeedEvaluator.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/SpeedRatioEvaluator.java26
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/SpeedVarianceClassifier.java124
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/SpeedVarianceEvaluator.java28
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/Stroke.java71
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/StrokeClassifier.java31
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java106
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/QWifiTile.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/Constants.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/Recents.java66
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java108
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java86
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/misc/DebugTrigger.java70
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java55
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java157
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/DebugOverlayView.java190
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java204
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewLayoutAlgorithm.java59
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java33
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java33
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java26
-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/KeyguardBouncer.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarApps.java310
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarAppsModel.java39
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java71
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java75
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiIcons.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java59
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarAppsModelTest.java34
-rw-r--r--packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp2
-rw-r--r--rs/jni/android_renderscript_RenderScript.cpp2
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java37
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AutoclickController.java395
-rw-r--r--services/accessibility/java/com/android/server/accessibility/TouchExplorer.java140
-rw-r--r--services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java59
-rw-r--r--services/backup/java/com/android/server/backup/BackupManagerService.java46
-rw-r--r--services/backup/java/com/android/server/backup/Trampoline.java10
-rw-r--r--services/core/java/com/android/server/BluetoothManagerService.java2
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java31
-rw-r--r--services/core/java/com/android/server/DeviceIdleController.java123
-rw-r--r--services/core/java/com/android/server/DropBoxManagerService.java6
-rw-r--r--services/core/java/com/android/server/EventLogTags.logtags3
-rw-r--r--services/core/java/com/android/server/GestureLauncherService.java35
-rw-r--r--services/core/java/com/android/server/InputMethodManagerService.java22
-rw-r--r--services/core/java/com/android/server/LocationManagerService.java7
-rw-r--r--services/core/java/com/android/server/LockSettingsService.java3
-rw-r--r--services/core/java/com/android/server/LockSettingsStrongAuth.java2
-rw-r--r--services/core/java/com/android/server/MmsServiceBroker.java2
-rw-r--r--services/core/java/com/android/server/MountService.java5
-rw-r--r--services/core/java/com/android/server/NetworkScoreService.java4
-rw-r--r--services/core/java/com/android/server/TextServicesManagerService.java2
-rw-r--r--services/core/java/com/android/server/ThermalObserver.java146
-rw-r--r--services/core/java/com/android/server/VibratorService.java4
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java194
-rw-r--r--services/core/java/com/android/server/am/ActivityStack.java216
-rw-r--r--services/core/java/com/android/server/am/ActivityStackSupervisor.java167
-rw-r--r--services/core/java/com/android/server/am/BatteryStatsService.java3
-rw-r--r--services/core/java/com/android/server/am/CompatModePackages.java5
-rw-r--r--services/core/java/com/android/server/am/EventLogTags.logtags4
-rw-r--r--services/core/java/com/android/server/am/ProviderMap.java2
-rw-r--r--services/core/java/com/android/server/am/TaskRecord.java2
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java9
-rw-r--r--services/core/java/com/android/server/connectivity/NetworkDiagnostics.java56
-rw-r--r--services/core/java/com/android/server/display/DisplayAdapter.java12
-rw-r--r--services/core/java/com/android/server/display/DisplayDevice.java2
-rw-r--r--services/core/java/com/android/server/display/DisplayDeviceInfo.java18
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java24
-rw-r--r--services/core/java/com/android/server/display/LocalDisplayAdapter.java236
-rw-r--r--services/core/java/com/android/server/display/LogicalDisplay.java26
-rw-r--r--services/core/java/com/android/server/display/OverlayDisplayAdapter.java2
-rw-r--r--services/core/java/com/android/server/fingerprint/FingerprintService.java25
-rw-r--r--services/core/java/com/android/server/firewall/SenderPackageFilter.java4
-rw-r--r--services/core/java/com/android/server/location/GeofenceProxy.java2
-rw-r--r--services/core/java/com/android/server/location/GpsLocationProvider.java350
-rw-r--r--services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java2
-rw-r--r--services/core/java/com/android/server/pm/Installer.java29
-rw-r--r--services/core/java/com/android/server/pm/PackageDexOptimizer.java32
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java158
-rw-r--r--services/core/java/com/android/server/policy/BarController.java2
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java329
-rw-r--r--services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java51
-rw-r--r--services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java26
-rw-r--r--services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java6
-rw-r--r--services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java11
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java14
-rw-r--r--services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java2
-rw-r--r--services/core/java/com/android/server/statusbar/StatusBarManagerService.java9
-rw-r--r--services/core/java/com/android/server/telecom/TelecomLoaderService.java2
-rw-r--r--services/core/java/com/android/server/tv/TvInputManagerService.java21
-rw-r--r--services/core/java/com/android/server/wm/AppTransition.java34
-rw-r--r--services/core/java/com/android/server/wm/AppWindowToken.java3
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java114
-rw-r--r--services/core/java/com/android/server/wm/DockedStackDividerController.java117
-rw-r--r--services/core/java/com/android/server/wm/DragState.java31
-rw-r--r--services/core/java/com/android/server/wm/InputMonitor.java2
-rw-r--r--services/core/java/com/android/server/wm/Task.java89
-rw-r--r--services/core/java/com/android/server/wm/TaskPositioner.java235
-rw-r--r--services/core/java/com/android/server/wm/TaskStack.java109
-rw-r--r--services/core/java/com/android/server/wm/WallpaperController.java3
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java232
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java124
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java116
-rw-r--r--services/core/java/com/android/server/wm/WindowSurfacePlacer.java32
-rw-r--r--services/core/jni/com_android_server_AlarmManagerService.cpp2
-rw-r--r--services/core/jni/com_android_server_AssetAtlasService.cpp2
-rw-r--r--services/core/jni/com_android_server_ConsumerIrService.cpp2
-rw-r--r--services/core/jni/com_android_server_PersistentDataBlockService.cpp2
-rw-r--r--services/core/jni/com_android_server_SerialService.cpp2
-rw-r--r--services/core/jni/com_android_server_SystemServer.cpp2
-rw-r--r--services/core/jni/com_android_server_UsbDeviceManager.cpp2
-rw-r--r--services/core/jni/com_android_server_UsbHostManager.cpp2
-rw-r--r--services/core/jni/com_android_server_VibratorService.cpp2
-rw-r--r--services/core/jni/com_android_server_am_ActivityManagerService.cpp1
-rw-r--r--services/core/jni/com_android_server_am_BatteryStatsService.cpp2
-rw-r--r--services/core/jni/com_android_server_connectivity_Vpn.cpp2
-rw-r--r--services/core/jni/com_android_server_hdmi_HdmiCecController.cpp2
-rw-r--r--services/core/jni/com_android_server_input_InputApplicationHandle.cpp2
-rw-r--r--services/core/jni/com_android_server_input_InputManagerService.cpp2
-rw-r--r--services/core/jni/com_android_server_input_InputWindowHandle.cpp2
-rw-r--r--services/core/jni/com_android_server_lights_LightsService.cpp2
-rw-r--r--services/core/jni/com_android_server_location_FlpHardwareProvider.cpp2
-rw-r--r--services/core/jni/com_android_server_location_GpsLocationProvider.cpp2
-rw-r--r--services/core/jni/com_android_server_power_PowerManagerService.cpp2
-rw-r--r--services/core/jni/com_android_server_tv_TvInputHal.cpp2
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java805
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/Owners.java14
-rw-r--r--services/java/com/android/server/SystemServer.java7
-rw-r--r--services/midi/java/com/android/server/midi/MidiService.java21
-rw-r--r--services/net/java/android/net/dhcp/DhcpClient.java5
-rw-r--r--services/net/java/android/net/ip/IpReachabilityMonitor.java (renamed from core/java/android/net/IpReachabilityMonitor.java)37
-rw-r--r--services/net/java/android/net/netlink/NetlinkConstants.java (renamed from core/java/android/net/netlink/NetlinkConstants.java)0
-rw-r--r--services/net/java/android/net/netlink/NetlinkErrorMessage.java (renamed from core/java/android/net/netlink/NetlinkErrorMessage.java)0
-rw-r--r--services/net/java/android/net/netlink/NetlinkMessage.java (renamed from core/java/android/net/netlink/NetlinkMessage.java)0
-rw-r--r--services/net/java/android/net/netlink/NetlinkSocket.java (renamed from core/java/android/net/netlink/NetlinkSocket.java)0
-rw-r--r--services/net/java/android/net/netlink/RtNetlinkNeighborMessage.java (renamed from core/java/android/net/netlink/RtNetlinkNeighborMessage.java)0
-rw-r--r--services/net/java/android/net/netlink/StructNdMsg.java (renamed from core/java/android/net/netlink/StructNdMsg.java)0
-rw-r--r--services/net/java/android/net/netlink/StructNdaCacheInfo.java (renamed from core/java/android/net/netlink/StructNdaCacheInfo.java)0
-rw-r--r--services/net/java/android/net/netlink/StructNlAttr.java (renamed from core/java/android/net/netlink/StructNlAttr.java)0
-rw-r--r--services/net/java/android/net/netlink/StructNlMsgErr.java (renamed from core/java/android/net/netlink/StructNlMsgErr.java)0
-rw-r--r--services/net/java/android/net/netlink/StructNlMsgHdr.java (renamed from core/java/android/net/netlink/StructNlMsgHdr.java)0
-rw-r--r--services/tests/servicestests/AndroidManifest.xml27
-rw-r--r--services/tests/servicestests/src/android/net/netlink/NetlinkErrorMessageTest.java (renamed from core/tests/coretests/src/android/net/netlink/NetlinkErrorMessageTest.java)0
-rw-r--r--services/tests/servicestests/src/android/net/netlink/NetlinkSocketTest.java (renamed from core/tests/coretests/src/android/net/netlink/NetlinkSocketTest.java)0
-rw-r--r--services/tests/servicestests/src/android/net/netlink/RtNetlinkNeighborMessageTest.java (renamed from core/tests/coretests/src/android/net/netlink/RtNetlinkNeighborMessageTest.java)0
-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.java241
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java592
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTestable.java36
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java371
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java15
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java50
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmins.java27
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java80
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java107
-rw-r--r--services/usage/java/com/android/server/usage/UnixCalendar.java50
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsDatabase.java17
-rw-r--r--services/usage/java/com/android/server/usage/UserUsageStatsService.java74
-rw-r--r--services/usb/java/com/android/server/usb/UsbDeviceManager.java7
-rw-r--r--services/usb/java/com/android/server/usb/UsbSettingsManager.java2
-rw-r--r--telecomm/java/android/telecom/Conference.java21
-rw-r--r--telecomm/java/android/telecom/Connection.java24
-rw-r--r--telecomm/java/android/telecom/ConnectionRequest.java33
-rw-r--r--telecomm/java/android/telecom/ConnectionService.java42
-rw-r--r--telecomm/java/android/telecom/TelecomManager.java43
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java19
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java5
-rw-r--r--telephony/java/com/android/internal/telephony/CallerInfo.java10
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl6
-rw-r--r--tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java3
-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/AndroidManifest.xml9
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/MultiProducerActivity.java347
-rw-r--r--tests/UiBench/Android.mk9
-rw-r--r--tests/UiBench/AndroidManifest.xml24
-rw-r--r--tests/UiBench/build.gradle7
-rw-r--r--tests/UiBench/res/drawable-nodpi/ball.jpgbin0 -> 20432 bytes
-rw-r--r--tests/UiBench/res/drawable-nodpi/block.jpgbin0 -> 20551 bytes
-rw-r--r--tests/UiBench/res/drawable-nodpi/ducky.jpgbin0 -> 23838 bytes
-rw-r--r--tests/UiBench/res/drawable-nodpi/frantic.jpgbin0 -> 192345 bytes
-rw-r--r--tests/UiBench/res/drawable-nodpi/jellies.jpgbin0 -> 24368 bytes
-rw-r--r--tests/UiBench/res/drawable-nodpi/mug.jpgbin0 -> 19839 bytes
-rw-r--r--tests/UiBench/res/drawable-nodpi/pencil.jpgbin0 -> 42976 bytes
-rw-r--r--tests/UiBench/res/drawable-nodpi/scissors.jpgbin0 -> 23209 bytes
-rw-r--r--tests/UiBench/res/drawable-nodpi/woot.jpgbin0 -> 36491 bytes
-rw-r--r--tests/UiBench/res/layout/activity_transition.xml103
-rw-r--r--tests/UiBench/res/layout/activity_transition_details.xml39
-rw-r--r--tests/UiBench/res/layout/recycler_view.xml21
-rw-r--r--tests/UiBench/src/com/android/test/uibench/ActivityTransition.java118
-rw-r--r--tests/UiBench/src/com/android/test/uibench/ActivityTransitionDetails.java63
-rw-r--r--tests/UiBench/src/com/android/test/uibench/InflatingListActivity.java2
-rw-r--r--tests/UiBench/src/com/android/test/uibench/TextCacheHighHitrateActivity.java2
-rw-r--r--tests/UiBench/src/com/android/test/uibench/TextCacheLowHitrateActivity.java2
-rw-r--r--tests/UiBench/src/com/android/test/uibench/TrivialListActivity.java2
-rw-r--r--tests/UiBench/src/com/android/test/uibench/TrivialRecyclerViewActivity.java28
-rw-r--r--tests/UiBench/src/com/android/test/uibench/listview/CompatListActivity.java (renamed from tests/UiBench/src/com/android/test/uibench/CompatListActivity.java)2
-rw-r--r--tests/UiBench/src/com/android/test/uibench/recyclerview/RvArrayAdapter.java64
-rw-r--r--tests/UiBench/src/com/android/test/uibench/recyclerview/RvCompatListActivity.java68
-rw-r--r--tests/VectorDrawableTest/res/drawable/vector_drawable01.xml8
-rw-r--r--tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawable01.java22
-rw-r--r--tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java2
-rw-r--r--tools/aapt2/Logger.h7
-rw-r--r--tools/aapt2/StringPiece.h5
-rw-r--r--tools/aapt2/Util.cpp93
-rw-r--r--tools/aapt2/Util.h1
-rw-r--r--tools/aapt2/Util_test.cpp7
-rw-r--r--tools/aidl4
-rw-r--r--tools/aidl/AST.cpp912
-rw-r--r--tools/aidl/AST.h371
-rw-r--r--tools/aidl/Android.mk80
-rw-r--r--tools/aidl/NOTICE190
-rw-r--r--tools/aidl/Type.cpp1245
-rw-r--r--tools/aidl/Type.h472
-rw-r--r--tools/aidl/aidl.cpp1072
-rw-r--r--tools/aidl/aidl.h9
-rw-r--r--tools/aidl/aidl_language.cpp94
-rw-r--r--tools/aidl/aidl_language.h189
-rw-r--r--tools/aidl/aidl_language_l.l196
-rw-r--r--tools/aidl/aidl_language_y.y343
-rw-r--r--tools/aidl/generate_java.cpp96
-rw-r--r--tools/aidl/generate_java.h32
-rw-r--r--tools/aidl/generate_java_binder.cpp560
-rw-r--r--tools/aidl/macros.h8
-rw-r--r--tools/aidl/main.cpp23
-rw-r--r--tools/aidl/options.cpp150
-rw-r--r--tools/aidl/options.h36
-rw-r--r--tools/aidl/options_unittest.cpp54
-rw-r--r--tools/aidl/search_path.cpp58
-rw-r--r--tools/aidl/search_path.h22
-rw-r--r--tools/aidl/test_main.cpp6
-rw-r--r--tools/aidl/tests/end_to_end_tests.cpp165
-rw-r--r--tools/aidl/tests/example_interface_test_data.cpp404
-rw-r--r--tools/aidl/tests/test_data.h33
-rw-r--r--tools/layoutlib/bridge/src/android/content/res/BridgeResources.java5
-rw-r--r--tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java20
-rw-r--r--tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java2
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java2
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java4
-rw-r--r--wifi/java/android/net/wifi/IWifiManager.aidl5
-rw-r--r--wifi/java/android/net/wifi/ScanInfo.aidl (renamed from tools/aidl/os.h)15
-rw-r--r--wifi/java/android/net/wifi/ScanInfo.java189
-rw-r--r--wifi/java/android/net/wifi/WifiManager.java24
824 files changed, 18251 insertions, 13507 deletions
diff --git a/Android.mk b/Android.mk
index d48887d17e3b..9029f4ef1f53 100644
--- a/Android.mk
+++ b/Android.mk
@@ -303,6 +303,7 @@ LOCAL_SRC_FILES += \
core/java/com/android/internal/textservice/ISpellCheckerSessionListener.aidl \
core/java/com/android/internal/textservice/ITextServicesManager.aidl \
core/java/com/android/internal/textservice/ITextServicesSessionListener.aidl \
+ core/java/com/android/internal/view/IDropPermissionHolder.aidl \
core/java/com/android/internal/view/IInputContext.aidl \
core/java/com/android/internal/view/IInputContextCallback.aidl \
core/java/com/android/internal/view/IInputMethod.aidl \
@@ -482,6 +483,7 @@ aidl_files := \
frameworks/base/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceInfo.aidl \
frameworks/base/wifi/java/android/net/wifi/WpsInfo.aidl \
frameworks/base/wifi/java/android/net/wifi/ScanResult.aidl \
+ frameworks/base/wifi/java/android/net/wifi/ScanInfo.aidl \
frameworks/base/wifi/java/android/net/wifi/WifiEnterpriseConfig.aidl \
frameworks/base/wifi/java/android/net/wifi/WifiConfiguration.aidl \
frameworks/base/wifi/java/android/net/wifi/WifiInfo.aidl \
diff --git a/api/current.txt b/api/current.txt
index d82927242b10..f963c1713a79 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -323,6 +323,7 @@ package android {
field public static final int buttonBarNeutralButtonStyle = 16843914; // 0x101048a
field public static final int buttonBarPositiveButtonStyle = 16843913; // 0x1010489
field public static final int buttonBarStyle = 16843566; // 0x101032e
+ field public static final int buttonGravity = 16844029; // 0x10104fd
field public static final int buttonStyle = 16842824; // 0x1010048
field public static final int buttonStyleInset = 16842826; // 0x101004a
field public static final int buttonStyleSmall = 16842825; // 0x1010049
@@ -372,6 +373,7 @@ package android {
field public static final int codes = 16843330; // 0x1010242
field public static final int collapseColumns = 16843083; // 0x101014b
field public static final int collapseContentDescription = 16843984; // 0x10104d0
+ field public static final int collapseIcon = 16844030; // 0x10104fe
field public static final int color = 16843173; // 0x10101a5
field public static final int colorAccent = 16843829; // 0x1010435
field public static final int colorActivatedHighlight = 16843664; // 0x1010390
@@ -412,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
@@ -777,6 +780,7 @@ package android {
field public static final int layout_y = 16843136; // 0x1010180
field public static final int left = 16843181; // 0x10101ad
field public static final int letterSpacing = 16843958; // 0x10104b6
+ field public static final int level = 16844031; // 0x10104ff
field public static final int lineSpacingExtra = 16843287; // 0x1010217
field public static final int lineSpacingMultiplier = 16843288; // 0x1010218
field public static final int lines = 16843092; // 0x1010154
@@ -809,6 +813,7 @@ package android {
field public static final int marqueeRepeatLimit = 16843293; // 0x101021d
field public static final int matchOrder = 16843855; // 0x101044f
field public static final int max = 16843062; // 0x1010136
+ field public static final int maxButtonHeight = 16844028; // 0x10104fc
field public static final int maxDate = 16843584; // 0x1010340
field public static final int maxEms = 16843095; // 0x1010157
field public static final int maxHeight = 16843040; // 0x1010120
@@ -1216,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
@@ -1284,6 +1290,11 @@ package android {
field public static final int tintMode = 16843771; // 0x10103fb
field public static final int title = 16843233; // 0x10101e1
field public static final int titleCondensed = 16843234; // 0x10101e2
+ field public static final int titleMargin = 16844023; // 0x10104f7
+ field public static final int titleMarginBottom = 16844027; // 0x10104fb
+ field public static final int titleMarginEnd = 16844025; // 0x10104f9
+ field public static final int titleMarginStart = 16844024; // 0x10104f8
+ field public static final int titleMarginTop = 16844026; // 0x10104fa
field public static final int titleTextAppearance = 16843822; // 0x101042e
field public static final int titleTextColor = 16844003; // 0x10104e3
field public static final int titleTextStyle = 16843512; // 0x10102f8
@@ -12303,7 +12314,6 @@ package android.graphics.drawable {
method public int getIntrinsicWidth();
method public int getLayoutDirection();
method public final int getLevel();
- method public final float getLevelFloat();
method public int getMinimumHeight();
method public int getMinimumWidth();
method public abstract int getOpacity();
@@ -12323,7 +12333,6 @@ package android.graphics.drawable {
method protected void onBoundsChange(android.graphics.Rect);
method public boolean onLayoutDirectionChanged(int);
method protected boolean onLevelChange(int);
- method protected boolean onLevelChange(float);
method protected boolean onStateChange(int[]);
method public static int resolveOpacity(int, int);
method public void scheduleSelf(java.lang.Runnable, long);
@@ -12341,15 +12350,12 @@ package android.graphics.drawable {
method public void setHotspotBounds(int, int, int, int);
method public final boolean setLayoutDirection(int);
method public final boolean setLevel(int);
- method public final boolean setLevel(float);
method public boolean setState(int[]);
method public void setTint(int);
method public void setTintList(android.content.res.ColorStateList);
method public void setTintMode(android.graphics.PorterDuff.Mode);
method public boolean setVisible(boolean, boolean);
method public void unscheduleSelf(java.lang.Runnable);
- field public static final int MAX_LEVEL = 10000; // 0x2710
- field public static final float MAX_LEVEL_FLOAT = 10000.0f;
}
public static abstract interface Drawable.Callback {
@@ -18247,6 +18253,7 @@ package android.net {
field public static final java.lang.String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
field public static final deprecated int DEFAULT_NETWORK_PREFERENCE = 1; // 0x1
field public static final java.lang.String EXTRA_CAPTIVE_PORTAL = "android.net.extra.CAPTIVE_PORTAL";
+ field public static final java.lang.String EXTRA_CAPTIVE_PORTAL_URL = "android.net.extra.CAPTIVE_PORTAL_URL";
field public static final java.lang.String EXTRA_EXTRA_INFO = "extraInfo";
field public static final java.lang.String EXTRA_IS_FAILOVER = "isFailover";
field public static final java.lang.String EXTRA_NETWORK = "android.net.extra.NETWORK";
@@ -19153,6 +19160,22 @@ package android.net.sip {
package android.net.wifi {
+ public class ScanInfo implements android.os.Parcelable {
+ ctor public ScanInfo(android.net.wifi.ScanResult);
+ ctor public ScanInfo(long, int, java.lang.String, java.lang.String, java.lang.String, java.lang.String, byte[], int);
+ method public int describeContents();
+ method public long getBssid();
+ method public byte[] getIconData();
+ method public java.lang.String getIconType();
+ method public java.lang.String getName();
+ method public int getOsuIdentity();
+ method public int getRssi();
+ method public android.net.wifi.ScanResult getScanResult();
+ method public java.lang.String getServiceDescription();
+ method public java.lang.String getSsid();
+ method public void writeToParcel(android.os.Parcel, int);
+ }
+
public class ScanResult implements android.os.Parcelable {
method public int describeContents();
method public boolean is80211mcResponder();
@@ -19353,6 +19376,7 @@ package android.net.wifi {
method public java.util.List<android.net.wifi.WifiConfiguration> getConfiguredNetworks();
method public android.net.wifi.WifiInfo getConnectionInfo();
method public android.net.DhcpInfo getDhcpInfo();
+ method public java.util.List<android.net.wifi.ScanInfo> getScanInfos();
method public java.util.List<android.net.wifi.ScanResult> getScanResults();
method public int getWifiState();
method public boolean is5GHzBandSupported();
@@ -19368,6 +19392,7 @@ package android.net.wifi {
method public boolean reconnect();
method public boolean removeNetwork(int);
method public boolean saveConfiguration();
+ method public void setOsuSelection(int);
method public void setTdlsEnabled(java.net.InetAddress, boolean);
method public void setTdlsEnabledWithMacAddress(java.lang.String, boolean);
method public boolean setWifiEnabled(boolean);
@@ -34807,6 +34832,7 @@ package android.view {
method public int getAction();
method public android.content.ClipData getClipData();
method public android.content.ClipDescription getClipDescription();
+ method public android.view.DropPermissionHolder getDropPermissionHolder();
method public java.lang.Object getLocalState();
method public boolean getResult();
method public float getX();
@@ -34821,6 +34847,14 @@ package android.view {
field public static final android.os.Parcelable.Creator<android.view.DragEvent> CREATOR;
}
+ public class DropPermissionHolder implements android.os.Parcelable {
+ method public int describeContents();
+ method public void grant();
+ method public void revoke();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.view.DropPermissionHolder> CREATOR;
+ }
+
public class FocusFinder {
method public android.view.View findNearestTouchable(android.view.ViewGroup, int, int, int, int[]);
method public final android.view.View findNextFocus(android.view.ViewGroup, android.view.View, int);
@@ -36509,6 +36543,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);
@@ -36524,6 +36559,11 @@ package android.view {
field public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0; // 0x0
field public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 1; // 0x1
field public static final android.util.Property<android.view.View, java.lang.Float> ALPHA;
+ field public static final int DRAG_FLAG_GLOBAL = 256; // 0x100
+ field public static final int DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION = 64; // 0x40
+ field public static final int DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION = 128; // 0x80
+ field public static final int DRAG_FLAG_GLOBAL_URI_READ = 1; // 0x1
+ field public static final int DRAG_FLAG_GLOBAL_URI_WRITE = 2; // 0x2
field public static final int DRAG_FLAG_OPAQUE = 512; // 0x200
field public static final int DRAWING_CACHE_QUALITY_AUTO = 0; // 0x0
field public static final int DRAWING_CACHE_QUALITY_HIGH = 1048576; // 0x100000
@@ -36970,6 +37010,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();
@@ -37091,6 +37132,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);
}
@@ -40955,6 +40997,7 @@ package android.widget {
method public void setInterpolator(android.view.animation.Interpolator);
method public synchronized void setMax(int);
method public synchronized void setProgress(int);
+ method public void setProgress(int, boolean);
method public void setProgressBackgroundTintList(android.content.res.ColorStateList);
method public void setProgressBackgroundTintMode(android.graphics.PorterDuff.Mode);
method public void setProgressDrawable(android.graphics.drawable.Drawable);
@@ -41951,6 +41994,10 @@ package android.widget {
method public int getPopupTheme();
method public java.lang.CharSequence getSubtitle();
method public java.lang.CharSequence getTitle();
+ method public int getTitleMarginBottom();
+ method public int getTitleMarginEnd();
+ method public int getTitleMarginStart();
+ method public int getTitleMarginTop();
method public boolean hasExpandedActionView();
method public boolean hideOverflowMenu();
method public void inflateMenu(int);
@@ -41976,6 +42023,11 @@ package android.widget {
method public void setSubtitleTextColor(int);
method public void setTitle(int);
method public void setTitle(java.lang.CharSequence);
+ method public void setTitleMargin(int, int, int, int);
+ method public void setTitleMarginBottom(int);
+ method public void setTitleMarginEnd(int);
+ method public void setTitleMarginStart(int);
+ method public void setTitleMarginTop(int);
method public void setTitleTextAppearance(android.content.Context, int);
method public void setTitleTextColor(int);
method public boolean showOverflowMenu();
diff --git a/api/system-current.txt b/api/system-current.txt
index 590505691085..1084f30be68f 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -415,6 +415,7 @@ package android {
field public static final int buttonBarNeutralButtonStyle = 16843914; // 0x101048a
field public static final int buttonBarPositiveButtonStyle = 16843913; // 0x1010489
field public static final int buttonBarStyle = 16843566; // 0x101032e
+ field public static final int buttonGravity = 16844029; // 0x10104fd
field public static final int buttonStyle = 16842824; // 0x1010048
field public static final int buttonStyleInset = 16842826; // 0x101004a
field public static final int buttonStyleSmall = 16842825; // 0x1010049
@@ -464,6 +465,7 @@ package android {
field public static final int codes = 16843330; // 0x1010242
field public static final int collapseColumns = 16843083; // 0x101014b
field public static final int collapseContentDescription = 16843984; // 0x10104d0
+ field public static final int collapseIcon = 16844030; // 0x10104fe
field public static final int color = 16843173; // 0x10101a5
field public static final int colorAccent = 16843829; // 0x1010435
field public static final int colorActivatedHighlight = 16843664; // 0x1010390
@@ -504,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
@@ -869,6 +872,7 @@ package android {
field public static final int layout_y = 16843136; // 0x1010180
field public static final int left = 16843181; // 0x10101ad
field public static final int letterSpacing = 16843958; // 0x10104b6
+ field public static final int level = 16844031; // 0x10104ff
field public static final int lineSpacingExtra = 16843287; // 0x1010217
field public static final int lineSpacingMultiplier = 16843288; // 0x1010218
field public static final int lines = 16843092; // 0x1010154
@@ -901,6 +905,7 @@ package android {
field public static final int marqueeRepeatLimit = 16843293; // 0x101021d
field public static final int matchOrder = 16843855; // 0x101044f
field public static final int max = 16843062; // 0x1010136
+ field public static final int maxButtonHeight = 16844028; // 0x10104fc
field public static final int maxDate = 16843584; // 0x1010340
field public static final int maxEms = 16843095; // 0x1010157
field public static final int maxHeight = 16843040; // 0x1010120
@@ -1312,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
@@ -1380,6 +1386,11 @@ package android {
field public static final int tintMode = 16843771; // 0x10103fb
field public static final int title = 16843233; // 0x10101e1
field public static final int titleCondensed = 16843234; // 0x10101e2
+ field public static final int titleMargin = 16844023; // 0x10104f7
+ field public static final int titleMarginBottom = 16844027; // 0x10104fb
+ field public static final int titleMarginEnd = 16844025; // 0x10104f9
+ field public static final int titleMarginStart = 16844024; // 0x10104f8
+ field public static final int titleMarginTop = 16844026; // 0x10104fa
field public static final int titleTextAppearance = 16843822; // 0x101042e
field public static final int titleTextColor = 16844003; // 0x10104e3
field public static final int titleTextStyle = 16843512; // 0x10102f8
@@ -12640,7 +12651,6 @@ package android.graphics.drawable {
method public int getIntrinsicWidth();
method public int getLayoutDirection();
method public final int getLevel();
- method public final float getLevelFloat();
method public int getMinimumHeight();
method public int getMinimumWidth();
method public abstract int getOpacity();
@@ -12660,7 +12670,6 @@ package android.graphics.drawable {
method protected void onBoundsChange(android.graphics.Rect);
method public boolean onLayoutDirectionChanged(int);
method protected boolean onLevelChange(int);
- method protected boolean onLevelChange(float);
method protected boolean onStateChange(int[]);
method public static int resolveOpacity(int, int);
method public void scheduleSelf(java.lang.Runnable, long);
@@ -12678,15 +12687,12 @@ package android.graphics.drawable {
method public void setHotspotBounds(int, int, int, int);
method public final boolean setLayoutDirection(int);
method public final boolean setLevel(int);
- method public final boolean setLevel(float);
method public boolean setState(int[]);
method public void setTint(int);
method public void setTintList(android.content.res.ColorStateList);
method public void setTintMode(android.graphics.PorterDuff.Mode);
method public boolean setVisible(boolean, boolean);
method public void unscheduleSelf(java.lang.Runnable);
- field public static final int MAX_LEVEL = 10000; // 0x2710
- field public static final float MAX_LEVEL_FLOAT = 10000.0f;
}
public static abstract interface Drawable.Callback {
@@ -19759,6 +19765,7 @@ package android.net {
field public static final java.lang.String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
field public static final deprecated int DEFAULT_NETWORK_PREFERENCE = 1; // 0x1
field public static final java.lang.String EXTRA_CAPTIVE_PORTAL = "android.net.extra.CAPTIVE_PORTAL";
+ field public static final java.lang.String EXTRA_CAPTIVE_PORTAL_URL = "android.net.extra.CAPTIVE_PORTAL_URL";
field public static final java.lang.String EXTRA_EXTRA_INFO = "extraInfo";
field public static final java.lang.String EXTRA_IS_FAILOVER = "isFailover";
field public static final java.lang.String EXTRA_NETWORK = "android.net.extra.NETWORK";
@@ -20906,6 +20913,22 @@ package android.net.wifi {
field public byte id;
}
+ public class ScanInfo implements android.os.Parcelable {
+ ctor public ScanInfo(android.net.wifi.ScanResult);
+ ctor public ScanInfo(long, int, java.lang.String, java.lang.String, java.lang.String, java.lang.String, byte[], int);
+ method public int describeContents();
+ method public long getBssid();
+ method public byte[] getIconData();
+ method public java.lang.String getIconType();
+ method public java.lang.String getName();
+ method public int getOsuIdentity();
+ method public int getRssi();
+ method public android.net.wifi.ScanResult getScanResult();
+ method public java.lang.String getServiceDescription();
+ method public java.lang.String getSsid();
+ method public void writeToParcel(android.os.Parcel, int);
+ }
+
public class ScanResult implements android.os.Parcelable {
method public int describeContents();
method public boolean is80211mcResponder();
@@ -21131,6 +21154,7 @@ package android.net.wifi {
method public android.net.wifi.WifiConnectionStatistics getConnectionStatistics();
method public android.net.DhcpInfo getDhcpInfo();
method public java.util.List<android.net.wifi.WifiConfiguration> getPrivilegedConfiguredNetworks();
+ method public java.util.List<android.net.wifi.ScanInfo> getScanInfos();
method public java.util.List<android.net.wifi.ScanResult> getScanResults();
method public int getWifiState();
method public boolean is5GHzBandSupported();
@@ -21150,6 +21174,7 @@ package android.net.wifi {
method public boolean reconnect();
method public boolean removeNetwork(int);
method public boolean saveConfiguration();
+ method public void setOsuSelection(int);
method public void setTdlsEnabled(java.net.InetAddress, boolean);
method public void setTdlsEnabledWithMacAddress(java.lang.String, boolean);
method public boolean setWifiEnabled(boolean);
@@ -25664,8 +25689,8 @@ package android.os {
ctor public UserHandle(android.os.Parcel);
method public int describeContents();
method public int getIdentifier();
- method public final boolean isOwner();
- method public static final int myUserId();
+ method public boolean isOwner();
+ method public static int myUserId();
method public static android.os.UserHandle readFromParcel(android.os.Parcel);
method public void writeToParcel(android.os.Parcel, int);
method public static void writeToParcel(android.os.UserHandle, android.os.Parcel);
@@ -32839,6 +32864,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";
@@ -37101,6 +37127,7 @@ package android.view {
method public int getAction();
method public android.content.ClipData getClipData();
method public android.content.ClipDescription getClipDescription();
+ method public android.view.DropPermissionHolder getDropPermissionHolder();
method public java.lang.Object getLocalState();
method public boolean getResult();
method public float getX();
@@ -37115,6 +37142,14 @@ package android.view {
field public static final android.os.Parcelable.Creator<android.view.DragEvent> CREATOR;
}
+ public class DropPermissionHolder implements android.os.Parcelable {
+ method public int describeContents();
+ method public void grant();
+ method public void revoke();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.view.DropPermissionHolder> CREATOR;
+ }
+
public class FocusFinder {
method public android.view.View findNearestTouchable(android.view.ViewGroup, int, int, int, int[]);
method public final android.view.View findNextFocus(android.view.ViewGroup, android.view.View, int);
@@ -38803,6 +38838,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);
@@ -38818,6 +38854,11 @@ package android.view {
field public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0; // 0x0
field public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 1; // 0x1
field public static final android.util.Property<android.view.View, java.lang.Float> ALPHA;
+ field public static final int DRAG_FLAG_GLOBAL = 256; // 0x100
+ field public static final int DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION = 64; // 0x40
+ field public static final int DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION = 128; // 0x80
+ field public static final int DRAG_FLAG_GLOBAL_URI_READ = 1; // 0x1
+ field public static final int DRAG_FLAG_GLOBAL_URI_WRITE = 2; // 0x2
field public static final int DRAG_FLAG_OPAQUE = 512; // 0x200
field public static final int DRAWING_CACHE_QUALITY_AUTO = 0; // 0x0
field public static final int DRAWING_CACHE_QUALITY_HIGH = 1048576; // 0x100000
@@ -39264,6 +39305,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();
@@ -39385,6 +39427,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);
}
@@ -43563,6 +43606,7 @@ package android.widget {
method public void setInterpolator(android.view.animation.Interpolator);
method public synchronized void setMax(int);
method public synchronized void setProgress(int);
+ method public void setProgress(int, boolean);
method public void setProgressBackgroundTintList(android.content.res.ColorStateList);
method public void setProgressBackgroundTintMode(android.graphics.PorterDuff.Mode);
method public void setProgressDrawable(android.graphics.drawable.Drawable);
@@ -44559,6 +44603,10 @@ package android.widget {
method public int getPopupTheme();
method public java.lang.CharSequence getSubtitle();
method public java.lang.CharSequence getTitle();
+ method public int getTitleMarginBottom();
+ method public int getTitleMarginEnd();
+ method public int getTitleMarginStart();
+ method public int getTitleMarginTop();
method public boolean hasExpandedActionView();
method public boolean hideOverflowMenu();
method public void inflateMenu(int);
@@ -44584,6 +44632,11 @@ package android.widget {
method public void setSubtitleTextColor(int);
method public void setTitle(int);
method public void setTitle(java.lang.CharSequence);
+ method public void setTitleMargin(int, int, int, int);
+ method public void setTitleMarginBottom(int);
+ method public void setTitleMarginEnd(int);
+ method public void setTitleMarginStart(int);
+ method public void setTitleMarginTop(int);
method public void setTitleTextAppearance(android.content.Context, int);
method public void setTitleTextColor(int);
method public boolean showOverflowMenu();
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 9709299fd16a..5c9fd51d606d 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -19,6 +19,8 @@
package com.android.commands.am;
import static android.app.ActivityManager.DOCKED_STACK_ID;
+import static android.app.ActivityManager.RESIZE_MODE_SYSTEM;
+import static android.app.ActivityManager.RESIZE_MODE_USER;
import android.app.ActivityManager;
import android.app.ActivityManager.StackInfo;
@@ -161,6 +163,7 @@ public class Am extends BaseCommand {
" am task drag-task-test <TASK_ID> <STEP_SIZE> [DELAY_MS] \n" +
" am task size-task-test <TASK_ID> <STEP_SIZE> [DELAY_MS] \n" +
" am get-config\n" +
+ " am suppress-resize-config-changes <true|false>\n" +
" am set-inactive [--user <USER_ID>] <PACKAGE> true|false\n" +
" am get-inactive [--user <USER_ID>] <PACKAGE>\n" +
" am send-trim-memory [--user <USER_ID>] <PROCESS>\n" +
@@ -324,6 +327,8 @@ public class Am extends BaseCommand {
"\n" +
"am get-config: retrieve the configuration and any recent configurations\n" +
" of the device.\n" +
+ "am suppress-resize-config-changes: suppresses configuration changes due to\n" +
+ " user resizing an activity/task.\n" +
"\n" +
"am set-inactive: sets the inactive state of an app.\n" +
"\n" +
@@ -451,6 +456,8 @@ public class Am extends BaseCommand {
runTask();
} else if (op.equals("get-config")) {
runGetConfig();
+ } else if (op.equals("suppress-resize-config-changes")) {
+ runSuppressResizeConfigChanges();
} else if (op.equals("set-inactive")) {
runSetInactive();
} else if (op.equals("get-inactive")) {
@@ -2266,12 +2273,13 @@ public class Am extends BaseCommand {
System.err.println("Error: invalid input bounds");
return;
}
- taskResize(taskId, bounds, 0);
+ taskResize(taskId, bounds, 0, false);
}
- private void taskResize(int taskId, Rect bounds, int delay_ms) {
+ private void taskResize(int taskId, Rect bounds, int delay_ms, boolean pretendUserResize) {
try {
- mAm.resizeTask(taskId, bounds);
+ final int resizeMode = pretendUserResize ? RESIZE_MODE_USER : RESIZE_MODE_SYSTEM;
+ mAm.resizeTask(taskId, bounds, resizeMode);
Thread.sleep(delay_ms);
} catch (RemoteException e) {
System.err.println("Error changing task bounds: " + e);
@@ -2354,7 +2362,7 @@ public class Am extends BaseCommand {
taskRect.top += maxMove;
taskRect.bottom += maxMove;
}
- taskResize(taskId, taskRect, delay_ms);
+ taskResize(taskId, taskRect, delay_ms, false);
}
} else {
while (maxToTravel < 0
@@ -2371,7 +2379,7 @@ public class Am extends BaseCommand {
taskRect.top -= maxMove;
taskRect.bottom -= maxMove;
}
- taskResize(taskId, taskRect, delay_ms);
+ taskResize(taskId, taskRect, delay_ms, false);
}
}
// Return the remaining distance we didn't travel because we reached the target location.
@@ -2405,7 +2413,7 @@ public class Am extends BaseCommand {
currentTaskBounds.left -= getStepSize(
currentTaskBounds.left, stackBounds.left, stepSize, GREATER_THAN_TARGET);
- taskResize(taskId, currentTaskBounds, delay_ms);
+ taskResize(taskId, currentTaskBounds, delay_ms, true);
} while (stackBounds.top < currentTaskBounds.top
|| stackBounds.left < currentTaskBounds.left);
@@ -2418,7 +2426,7 @@ public class Am extends BaseCommand {
currentTaskBounds.left += getStepSize(
currentTaskBounds.left, initialTaskBounds.left, stepSize, !GREATER_THAN_TARGET);
- taskResize(taskId, currentTaskBounds, delay_ms);
+ taskResize(taskId, currentTaskBounds, delay_ms, true);
} while (initialTaskBounds.top > currentTaskBounds.top
|| initialTaskBounds.left > currentTaskBounds.left);
@@ -2431,7 +2439,7 @@ public class Am extends BaseCommand {
currentTaskBounds.right += getStepSize(
currentTaskBounds.right, stackBounds.right, stepSize, !GREATER_THAN_TARGET);
- taskResize(taskId, currentTaskBounds, delay_ms);
+ taskResize(taskId, currentTaskBounds, delay_ms, true);
} while (stackBounds.top < currentTaskBounds.top
|| stackBounds.right > currentTaskBounds.right);
@@ -2444,7 +2452,7 @@ public class Am extends BaseCommand {
currentTaskBounds.right -= getStepSize(currentTaskBounds.right, initialTaskBounds.right,
stepSize, GREATER_THAN_TARGET);
- taskResize(taskId, currentTaskBounds, delay_ms);
+ taskResize(taskId, currentTaskBounds, delay_ms, true);
} while (initialTaskBounds.top > currentTaskBounds.top
|| initialTaskBounds.right < currentTaskBounds.right);
@@ -2457,7 +2465,7 @@ public class Am extends BaseCommand {
currentTaskBounds.left -= getStepSize(
currentTaskBounds.left, stackBounds.left, stepSize, GREATER_THAN_TARGET);
- taskResize(taskId, currentTaskBounds, delay_ms);
+ taskResize(taskId, currentTaskBounds, delay_ms, true);
} while (stackBounds.bottom > currentTaskBounds.bottom
|| stackBounds.left < currentTaskBounds.left);
@@ -2470,7 +2478,7 @@ public class Am extends BaseCommand {
currentTaskBounds.left += getStepSize(
currentTaskBounds.left, initialTaskBounds.left, stepSize, !GREATER_THAN_TARGET);
- taskResize(taskId, currentTaskBounds, delay_ms);
+ taskResize(taskId, currentTaskBounds, delay_ms, true);
} while (initialTaskBounds.bottom < currentTaskBounds.bottom
|| initialTaskBounds.left > currentTaskBounds.left);
@@ -2483,7 +2491,7 @@ public class Am extends BaseCommand {
currentTaskBounds.right += getStepSize(
currentTaskBounds.right, stackBounds.right, stepSize, !GREATER_THAN_TARGET);
- taskResize(taskId, currentTaskBounds, delay_ms);
+ taskResize(taskId, currentTaskBounds, delay_ms, true);
} while (stackBounds.bottom > currentTaskBounds.bottom
|| stackBounds.right > currentTaskBounds.right);
@@ -2496,7 +2504,7 @@ public class Am extends BaseCommand {
currentTaskBounds.right -= getStepSize(currentTaskBounds.right, initialTaskBounds.right,
stepSize, GREATER_THAN_TARGET);
- taskResize(taskId, currentTaskBounds, delay_ms);
+ taskResize(taskId, currentTaskBounds, delay_ms, true);
} while (initialTaskBounds.bottom < currentTaskBounds.bottom
|| initialTaskBounds.right < currentTaskBounds.right);
}
@@ -2603,6 +2611,16 @@ public class Am extends BaseCommand {
}
}
+ private void runSuppressResizeConfigChanges() throws Exception {
+ boolean suppress = Boolean.valueOf(nextArgRequired());
+
+ try {
+ mAm.suppressResizeConfigChanges(suppress);
+ } catch (RemoteException e) {
+ System.err.println("Error suppressing resize config changes: " + e);
+ }
+ }
+
private void runSetInactive() throws Exception {
int userId = UserHandle.USER_CURRENT;
diff --git a/cmds/svc/src/com/android/commands/svc/NfcCommand.java b/cmds/svc/src/com/android/commands/svc/NfcCommand.java
new file mode 100644
index 000000000000..e0f09ee2c666
--- /dev/null
+++ b/cmds/svc/src/com/android/commands/svc/NfcCommand.java
@@ -0,0 +1,85 @@
+/*
+ * 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.commands.svc;
+
+import android.content.Context;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
+import android.nfc.INfcAdapter;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
+public class NfcCommand extends Svc.Command {
+
+ public NfcCommand() {
+ super("nfc");
+ }
+
+ @Override
+ public String shortHelp() {
+ return "Control NFC functions";
+ }
+
+ @Override
+ public String longHelp() {
+ return shortHelp() + "\n"
+ + "\n"
+ + "usage: svc nfc [enable|disable]\n"
+ + " Turn NFC on or off.\n\n";
+ }
+
+ @Override
+ public void run(String[] args) {
+ boolean validCommand = false;
+ if (args.length >= 2) {
+ boolean flag = false;
+ if ("enable".equals(args[1])) {
+ flag = true;
+ validCommand = true;
+ } else if ("disable".equals(args[1])) {
+ flag = false;
+ validCommand = true;
+ }
+ if (validCommand) {
+ IPackageManager pm = IPackageManager.Stub.asInterface(
+ ServiceManager.getService("package"));
+ try {
+ if (pm.hasSystemFeature(PackageManager.FEATURE_NFC)) {
+ INfcAdapter nfc = INfcAdapter.Stub
+ .asInterface(ServiceManager.getService(Context.NFC_SERVICE));
+ try {
+ if (flag) {
+ nfc.enable();
+ } else
+ nfc.disable(true);
+ } catch (RemoteException e) {
+ System.err.println("NFC operation failed: " + e);
+ }
+ } else {
+ System.err.println("NFC feature not supported.");
+ }
+ } catch (RemoteException e) {
+ System.err.println("RemoteException while calling PackageManager, is the "
+ + "system running?");
+ }
+ return;
+ }
+ }
+ System.err.println(longHelp());
+ }
+
+}
diff --git a/cmds/svc/src/com/android/commands/svc/Svc.java b/cmds/svc/src/com/android/commands/svc/Svc.java
index 0fbba11e927d..2cccd1a4dc92 100644
--- a/cmds/svc/src/com/android/commands/svc/Svc.java
+++ b/cmds/svc/src/com/android/commands/svc/Svc.java
@@ -95,6 +95,7 @@ public class Svc {
new PowerCommand(),
new DataCommand(),
new WifiCommand(),
- new UsbCommand()
+ new UsbCommand(),
+ new NfcCommand(),
};
}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index f7dcf02da0a5..4997dc751082 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -4879,7 +4879,8 @@ public class Activity extends ContextThemeWrapper
if (Looper.myLooper() != mMainThread.getLooper()) {
throw new IllegalStateException("Must be called from main thread");
}
- mMainThread.requestRelaunchActivity(mToken, null, null, 0, false, null, null, false);
+ mMainThread.requestRelaunchActivity(mToken, null, null, 0, false, null, null, false,
+ false /* preserveWindow */);
}
/**
@@ -6223,12 +6224,13 @@ public class Activity extends ContextThemeWrapper
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
- Configuration config, String referrer, IVoiceInteractor voiceInteractor) {
+ Configuration config, String referrer, IVoiceInteractor voiceInteractor,
+ Window window) {
attachBaseContext(context);
mFragments.attachHost(null /*parent*/);
- mWindow = new PhoneWindow(this);
+ mWindow = new PhoneWindow(this, window);
mWindow.setWindowControllerCallback(this);
mWindow.setCallback(this);
mWindow.setOnWindowDismissedCallback(this);
@@ -6317,11 +6319,15 @@ public class Activity extends ContextThemeWrapper
final void performRestart() {
mFragments.noteStateNotSaved();
+ if (mToken != null && mParent == null) {
+ // We might have view roots that were preserved during a relaunch, we need to start them
+ // again. We don't need to check mStopped, the roots will check if they were actually
+ // stopped.
+ WindowManagerGlobal.getInstance().setStoppedState(mToken, false /* stopped */);
+ }
+
if (mStopped) {
mStopped = false;
- if (mToken != null && mParent == null) {
- WindowManagerGlobal.getInstance().setStoppedState(mToken, false);
- }
synchronized (mManagedCursors) {
final int N = mManagedCursors.size();
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index eeae20fa1ccf..4191dce79be8 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -452,6 +452,45 @@ public class ActivityManager {
*/
public static final int FIRST_DYNAMIC_STACK_ID = LAST_STATIC_STACK_ID + 1;
+ /**
+ * Input parameter to {@link android.app.IActivityManager#moveTaskToDockedStack} which
+ * specifies the position of the created docked stack at the top half of the screen if
+ * in portrait mode or at the left half of the screen if in landscape mode.
+ * @hide
+ */
+ public static final int DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT = 0;
+
+ /**
+ * Input parameter to {@link android.app.IActivityManager#moveTaskToDockedStack} which
+ * specifies the position of the created docked stack at the bottom half of the screen if
+ * in portrait mode or at the right half of the screen if in landscape mode.
+ * @hide
+ */
+ 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).
+ * @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).
+ * @hide
+ */
+ public static final int RESIZE_MODE_USER = 1;
+
+ /**
+ * 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;
+
/** @hide */
public int getFrontActivityScreenCompatMode() {
try {
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index d1c73bc945ff..cb1a89fd6601 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -743,6 +743,16 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
return true;
}
+ case MOVE_TASK_TO_DOCKED_STACK_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ int taskId = data.readInt();
+ int createMode = data.readInt();
+ boolean toTop = data.readInt() != 0;
+ moveTaskToDockedStack(taskId, createMode, toTop);
+ reply.writeNoException();
+ return true;
+ }
+
case RESIZE_STACK_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
int stackId = data.readInt();
@@ -2442,8 +2452,9 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
case RESIZE_TASK_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
int taskId = data.readInt();
+ int resizeMode = data.readInt();
Rect r = Rect.CREATOR.createFromParcel(data);
- resizeTask(taskId, r);
+ resizeTask(taskId, r, resizeMode);
reply.writeNoException();
return true;
}
@@ -2671,6 +2682,13 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
reportSizeConfigurations(token, horizontal, vertical);
return true;
}
+ case SUPPRESS_RESIZE_CONFIG_CHANGES_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ final boolean suppress = data.readInt() == 1;
+ suppressResizeConfigChanges(suppress);
+ reply.writeNoException();
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
@@ -3510,6 +3528,21 @@ class ActivityManagerProxy implements IActivityManager
reply.recycle();
}
@Override
+ public void moveTaskToDockedStack(int taskId, int createMode, boolean toTop)
+ throws RemoteException
+ {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeInt(taskId);
+ data.writeInt(createMode);
+ data.writeInt(toTop ? 1 : 0);
+ mRemote.transact(MOVE_TASK_TO_DOCKED_STACK_TRANSACTION, data, reply, 0);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
+ @Override
public void resizeStack(int stackId, Rect r) throws RemoteException
{
Parcel data = Parcel.obtain();
@@ -5874,12 +5907,13 @@ class ActivityManagerProxy implements IActivityManager
}
@Override
- public void resizeTask(int taskId, Rect r) throws RemoteException
+ public void resizeTask(int taskId, Rect r, int resizeMode) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeInt(taskId);
+ data.writeInt(resizeMode);
r.writeToParcel(data, 0);
mRemote.transact(RESIZE_TASK_TRANSACTION, data, reply, 0);
reply.readException();
@@ -6189,5 +6223,17 @@ class ActivityManagerProxy implements IActivityManager
reply.recycle();
}
+ @Override
+ public void suppressResizeConfigChanges(boolean suppress) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeInt(suppress ? 1 : 0);
+ mRemote.transact(SUPPRESS_RESIZE_CONFIG_CHANGES_TRANSACTION, data, reply, 0);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
+
private IBinder mRemote;
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 67dee7f43c32..4b8efab3e59e 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -315,8 +315,9 @@ public final class ActivityThread {
int pendingConfigChanges;
boolean onlyLocalRequest;
- View mPendingRemoveWindow;
+ Window mPendingRemoveWindow;
WindowManager mPendingRemoveWindowManager;
+ boolean mPreserveWindow;
ActivityClientRecord() {
parent = null;
@@ -670,9 +671,9 @@ public final class ActivityThread {
public final void scheduleRelaunchActivity(IBinder token,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
int configChanges, boolean notResumed, Configuration config,
- Configuration overrideConfig) {
+ Configuration overrideConfig, boolean preserveWindow) {
requestRelaunchActivity(token, pendingResults, pendingNewIntents,
- configChanges, notResumed, config, overrideConfig, true);
+ configChanges, notResumed, config, overrideConfig, true, preserveWindow);
}
public final void scheduleNewIntent(List<ReferrerIntent> intents, IBinder token) {
@@ -2376,10 +2377,16 @@ public final class ActivityThread {
Configuration config = new Configuration(mCompatConfiguration);
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
+ r.activityInfo.name + " with config " + config);
+ Window window = null;
+ if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
+ window = r.mPendingRemoveWindow;
+ r.mPendingRemoveWindow = null;
+ r.mPendingRemoveWindowManager = null;
+ }
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
- r.referrer, r.voiceInteractor);
+ r.referrer, r.voiceInteractor, window);
if (customIntent != null) {
activity.mIntent = customIntent;
@@ -3191,10 +3198,14 @@ public final class ActivityThread {
return r;
}
- static final void cleanUpPendingRemoveWindows(ActivityClientRecord r) {
+ static final void cleanUpPendingRemoveWindows(ActivityClientRecord r, boolean force) {
+ if (r.mPreserveWindow && !force) {
+ return;
+ }
if (r.mPendingRemoveWindow != null) {
- r.mPendingRemoveWindowManager.removeViewImmediate(r.mPendingRemoveWindow);
- IBinder wtoken = r.mPendingRemoveWindow.getWindowToken();
+ r.mPendingRemoveWindowManager.removeViewImmediate(
+ r.mPendingRemoveWindow.getDecorView());
+ IBinder wtoken = r.mPendingRemoveWindow.getDecorView().getWindowToken();
if (wtoken != null) {
WindowManagerGlobal.getInstance().closeAll(wtoken,
r.activity.getClass().getName(), "Activity");
@@ -3245,7 +3256,11 @@ public final class ActivityThread {
a.mDecor = decor;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |= forwardBit;
- if (a.mVisibleFromClient) {
+ if (r.mPreserveWindow) {
+ a.mWindowAdded = true;
+ r.mPreserveWindow = false;
+ }
+ if (a.mVisibleFromClient && !a.mWindowAdded) {
a.mWindowAdded = true;
wm.addView(decor, l);
}
@@ -3260,7 +3275,7 @@ public final class ActivityThread {
}
// Get rid of anything left hanging around.
- cleanUpPendingRemoveWindows(r);
+ cleanUpPendingRemoveWindows(r, false /* force */);
// The window is now visible if it has been added, we are not
// simply finishing, and we are not starting another activity.
@@ -3745,7 +3760,8 @@ public final class ActivityThread {
// request all activities to relaunch for the changes to take place
for (Map.Entry<IBinder, ActivityClientRecord> entry : mActivities.entrySet()) {
- requestRelaunchActivity(entry.getKey(), null, null, 0, false, null, null, false);
+ requestRelaunchActivity(entry.getKey(), null, null, 0, false, null, null, false,
+ false /* preserveWindow */);
}
}
}
@@ -3931,7 +3947,7 @@ public final class ActivityThread {
ActivityClientRecord r = performDestroyActivity(token, finishing,
configChanges, getNonConfigInstance);
if (r != null) {
- cleanUpPendingRemoveWindows(r);
+ cleanUpPendingRemoveWindows(r, finishing);
WindowManager wm = r.activity.getWindowManager();
View v = r.activity.mDecor;
if (v != null) {
@@ -3940,11 +3956,18 @@ public final class ActivityThread {
}
IBinder wtoken = v.getWindowToken();
if (r.activity.mWindowAdded) {
- if (r.onlyLocalRequest) {
+ boolean reuseForResize = r.window.hasNonClientDecorView() && r.mPreserveWindow;
+ if (r.onlyLocalRequest || reuseForResize) {
// Hold off on removing this until the new activity's
// window is being added.
- r.mPendingRemoveWindow = v;
+ r.mPendingRemoveWindow = r.window;
r.mPendingRemoveWindowManager = wm;
+ if (reuseForResize) {
+ // We can only keep the part of the view hierarchy that we control,
+ // everything else must be removed, because it might not be able to
+ // behave properly when activity is relaunching.
+ r.window.clearContentView();
+ }
} else {
wm.removeViewImmediate(v);
}
@@ -3986,10 +4009,14 @@ public final class ActivityThread {
mSomeActivitiesChanged = true;
}
+ /**
+ * @param preserveWindow Whether the activity should try to reuse the window it created,
+ * including the decor view after the relaunch.
+ */
public final void requestRelaunchActivity(IBinder token,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
int configChanges, boolean notResumed, Configuration config,
- Configuration overrideConfig, boolean fromServer) {
+ Configuration overrideConfig, boolean fromServer, boolean preserveWindow) {
ActivityClientRecord target = null;
synchronized (mResourcesManager) {
@@ -4020,6 +4047,7 @@ public final class ActivityThread {
target.token = token;
target.pendingResults = pendingResults;
target.pendingIntents = pendingNewIntents;
+ target.mPreserveWindow = preserveWindow;
if (!fromServer) {
ActivityClientRecord existing = mActivities.get(token);
if (existing != null) {
@@ -4120,6 +4148,7 @@ public final class ActivityThread {
r.activity.mConfigChangeFlags |= configChanges;
r.onlyLocalRequest = tmp.onlyLocalRequest;
+ r.mPreserveWindow = tmp.mPreserveWindow;
Intent currentIntent = r.activity.mIntent;
r.activity.mChangingConfigurations = true;
diff --git a/core/java/android/app/ActivityTransitionState.java b/core/java/android/app/ActivityTransitionState.java
index 5c6fe46b0ef3..38562dacbcfd 100644
--- a/core/java/android/app/ActivityTransitionState.java
+++ b/core/java/android/app/ActivityTransitionState.java
@@ -150,7 +150,13 @@ class ActivityTransitionState {
}
public void setEnterActivityOptions(Activity activity, ActivityOptions options) {
- if (activity.getWindow().hasFeature(Window.FEATURE_ACTIVITY_TRANSITIONS)
+ final Window window = activity.getWindow();
+ if (window == null) {
+ return;
+ }
+ // ensure Decor View has been created so that the window features are activated
+ window.getDecorView();
+ if (window.hasFeature(Window.FEATURE_ACTIVITY_TRANSITIONS)
&& options != null && mEnterActivityOptions == null
&& mEnterTransitionCoordinator == null
&& options.getAnimationType() == ActivityOptions.ANIM_SCENE_TRANSITION) {
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 0cd02dd397c1..5544a7150625 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -93,8 +93,8 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
-/*package*/
-final class ApplicationPackageManager extends PackageManager {
+/** @hide */
+public class ApplicationPackageManager extends PackageManager {
private static final String TAG = "ApplicationPackageManager";
private final static boolean DEBUG_ICONS = false;
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index f164a0a76d8f..bead625a0bc1 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -63,14 +63,14 @@ public abstract class ApplicationThreadNative extends Binder
if (in != null) {
return in;
}
-
+
return new ApplicationThreadProxy(obj);
}
-
+
public ApplicationThreadNative() {
attachInterface(this, descriptor);
}
-
+
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
@@ -96,7 +96,7 @@ public abstract class ApplicationThreadNative extends Binder
scheduleStopActivity(b, show, configChanges);
return true;
}
-
+
case SCHEDULE_WINDOW_VISIBILITY_TRANSACTION:
{
data.enforceInterface(IApplicationThread.descriptor);
@@ -125,7 +125,7 @@ public abstract class ApplicationThreadNative extends Binder
scheduleResumeActivity(b, procState, isForward, resumeArgs);
return true;
}
-
+
case SCHEDULE_SEND_RESULT_TRANSACTION:
{
data.enforceInterface(IApplicationThread.descriptor);
@@ -179,7 +179,9 @@ public abstract class ApplicationThreadNative extends Binder
if (data.readInt() != 0) {
overrideConfig = Configuration.CREATOR.createFromParcel(data);
}
- scheduleRelaunchActivity(b, ri, pi, configChanges, notResumed, config, overrideConfig);
+ boolean preserveWindows = data.readInt() == 1;
+ scheduleRelaunchActivity(b, ri, pi, configChanges, notResumed, config, overrideConfig,
+ preserveWindows);
return true;
}
@@ -201,7 +203,7 @@ public abstract class ApplicationThreadNative extends Binder
scheduleDestroyActivity(b, finishing, configChanges);
return true;
}
-
+
case SCHEDULE_RECEIVER_TRANSACTION:
{
data.enforceInterface(IApplicationThread.descriptor);
@@ -371,7 +373,7 @@ public abstract class ApplicationThreadNative extends Binder
}
return true;
}
-
+
case DUMP_PROVIDER_TRANSACTION: {
data.enforceInterface(IApplicationThread.descriptor);
ParcelFileDescriptor fd = data.readFileDescriptor();
@@ -731,15 +733,15 @@ public abstract class ApplicationThreadNative extends Binder
class ApplicationThreadProxy implements IApplicationThread {
private final IBinder mRemote;
-
+
public ApplicationThreadProxy(IBinder remote) {
mRemote = remote;
}
-
+
public final IBinder asBinder() {
return mRemote;
}
-
+
public final void schedulePauseActivity(IBinder token, boolean finished,
boolean userLeaving, int configChanges, boolean dontReport) throws RemoteException {
Parcel data = Parcel.obtain();
@@ -856,7 +858,7 @@ class ApplicationThreadProxy implements IApplicationThread {
public final void scheduleRelaunchActivity(IBinder token,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
int configChanges, boolean notResumed, Configuration config,
- Configuration overrideConfig) throws RemoteException {
+ Configuration overrideConfig, boolean preserveWindow) throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
data.writeStrongBinder(token);
@@ -871,6 +873,7 @@ class ApplicationThreadProxy implements IApplicationThread {
} else {
data.writeInt(0);
}
+ data.writeInt(preserveWindow ? 1 : 0);
mRemote.transact(SCHEDULE_RELAUNCH_ACTIVITY_TRANSACTION, data, null,
IBinder.FLAG_ONEWAY);
data.recycle();
@@ -898,7 +901,7 @@ class ApplicationThreadProxy implements IApplicationThread {
IBinder.FLAG_ONEWAY);
data.recycle();
}
-
+
public final void scheduleReceiver(Intent intent, ActivityInfo info,
CompatibilityInfo compatInfo, int resultCode, String resultData,
Bundle map, boolean sync, int sendingUser, int processState) throws RemoteException {
@@ -940,7 +943,7 @@ class ApplicationThreadProxy implements IApplicationThread {
IBinder.FLAG_ONEWAY);
data.recycle();
}
-
+
public final void scheduleCreateService(IBinder token, ServiceInfo info,
CompatibilityInfo compatInfo, int processState) throws RemoteException {
Parcel data = Parcel.obtain();
@@ -1055,7 +1058,7 @@ class ApplicationThreadProxy implements IApplicationThread {
IBinder.FLAG_ONEWAY);
data.recycle();
}
-
+
public final void scheduleExit() throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
@@ -1128,7 +1131,7 @@ class ApplicationThreadProxy implements IApplicationThread {
mRemote.transact(DUMP_SERVICE_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);
data.recycle();
}
-
+
public void dumpProvider(FileDescriptor fd, IBinder token, String[] args)
throws RemoteException {
Parcel data = Parcel.obtain();
diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java
index 84cbea9b24bc..9081ef8a1d1a 100644
--- a/core/java/android/app/BackStackRecord.java
+++ b/core/java/android/app/BackStackRecord.java
@@ -1078,8 +1078,8 @@ final class BackStackRecord extends FragmentTransaction implements
*/
private ArrayList<View> addTransitionTargets(final TransitionState state,
final Transition enterTransition, final TransitionSet sharedElementTransition,
- final Transition overallTransition, final View container,
- final Fragment inFragment, final Fragment outFragment,
+ final Transition exitTransition, final Transition overallTransition,
+ final View container, final Fragment inFragment, final Fragment outFragment,
final ArrayList<View> hiddenFragmentViews, final boolean isBack,
final ArrayList<View> sharedElementTargets) {
if (enterTransition == null && sharedElementTransition == null &&
@@ -1103,6 +1103,13 @@ final class BackStackRecord extends FragmentTransaction implements
if (sharedElementTransition != null) {
namedViews = mapSharedElementsIn(state, isBack, inFragment);
removeTargets(sharedElementTransition, sharedElementTargets);
+ // keep the nonExistentView as excluded so the list doesn't get emptied
+ sharedElementTargets.remove(state.nonExistentView);
+ excludeViews(exitTransition, sharedElementTransition,
+ sharedElementTargets, false);
+ excludeViews(enterTransition, sharedElementTransition,
+ sharedElementTargets, false);
+
setSharedElementTargets(sharedElementTransition,
state.nonExistentView, namedViews, sharedElementTargets);
@@ -1126,6 +1133,12 @@ final class BackStackRecord extends FragmentTransaction implements
}
setSharedElementEpicenter(enterTransition, state);
}
+
+ excludeViews(exitTransition, enterTransition, enteringViews, true);
+ excludeViews(exitTransition, sharedElementTransition, sharedElementTargets,
+ true);
+ excludeViews(enterTransition, sharedElementTransition, sharedElementTargets,
+ true);
return true;
}
});
@@ -1279,6 +1292,9 @@ final class BackStackRecord extends FragmentTransaction implements
if (exitingViews == null || exitingViews.isEmpty()) {
exitTransition = null;
}
+ excludeViews(enterTransition, exitTransition, exitingViews, true);
+ excludeViews(enterTransition, sharedElementTransition, sharedElementTargets, true);
+ excludeViews(exitTransition, sharedElementTransition, sharedElementTargets, true);
// Set the epicenter of the exit transition
if (mSharedElementTargetNames != null && namedViews != null) {
@@ -1299,7 +1315,7 @@ final class BackStackRecord extends FragmentTransaction implements
if (transition != null) {
ArrayList<View> hiddenFragments = new ArrayList<View>();
ArrayList<View> enteringViews = addTransitionTargets(state, enterTransition,
- sharedElementTransition, transition, sceneRoot, inFragment,
+ sharedElementTransition, exitTransition, transition, sceneRoot, inFragment,
outFragment, hiddenFragments, isBack, sharedElementTargets);
transition.setNameOverrides(state.nameOverrides);
@@ -1379,6 +1395,16 @@ final class BackStackRecord extends FragmentTransaction implements
return false;
}
+ private static void excludeViews(Transition transition, Transition fromTransition,
+ ArrayList<View> views, boolean exclude) {
+ if (transition != null) {
+ final int viewCount = fromTransition == null ? 0 : views.size();
+ for (int i = 0; i < viewCount; i++) {
+ transition.excludeTarget(views.get(i), exclude);
+ }
+ }
+ }
+
/**
* After the transition has started, remove all targets that we added to the transitions
* so that the transitions are left in a clean state.
@@ -1396,9 +1422,15 @@ final class BackStackRecord extends FragmentTransaction implements
sceneRoot.getViewTreeObserver().removeOnPreDrawListener(this);
if (enterTransition != null) {
removeTargets(enterTransition, enteringViews);
+ excludeViews(enterTransition, exitTransition, exitingViews, false);
+ excludeViews(enterTransition, sharedElementTransition, sharedElementTargets,
+ false);
}
if (exitTransition != null) {
removeTargets(exitTransition, exitingViews);
+ excludeViews(exitTransition, enterTransition, enteringViews, false);
+ excludeViews(exitTransition, sharedElementTransition, sharedElementTargets,
+ false);
}
if (sharedElementTransition != null) {
removeTargets(sharedElementTransition, sharedElementTargets);
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index f70423fbbc9a..b44aab717174 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -63,6 +63,7 @@ final class FragmentState implements Parcelable {
final boolean mRetainInstance;
final boolean mDetached;
final Bundle mArguments;
+ final boolean mHidden;
Bundle mSavedFragmentState;
@@ -78,6 +79,7 @@ final class FragmentState implements Parcelable {
mRetainInstance = frag.mRetainInstance;
mDetached = frag.mDetached;
mArguments = frag.mArguments;
+ mHidden = frag.mHidden;
}
public FragmentState(Parcel in) {
@@ -90,6 +92,7 @@ final class FragmentState implements Parcelable {
mRetainInstance = in.readInt() != 0;
mDetached = in.readInt() != 0;
mArguments = in.readBundle();
+ mHidden = in.readInt() != 0;
mSavedFragmentState = in.readBundle();
}
@@ -117,6 +120,7 @@ final class FragmentState implements Parcelable {
mInstance.mTag = mTag;
mInstance.mRetainInstance = mRetainInstance;
mInstance.mDetached = mDetached;
+ mInstance.mHidden = mHidden;
mInstance.mFragmentManager = host.mFragmentManager;
if (FragmentManagerImpl.DEBUG) Log.v(FragmentManagerImpl.TAG,
"Instantiated fragment " + mInstance);
@@ -138,6 +142,7 @@ final class FragmentState implements Parcelable {
dest.writeInt(mRetainInstance ? 1 : 0);
dest.writeInt(mDetached ? 1 : 0);
dest.writeBundle(mArguments);
+ dest.writeInt(mHidden ? 1 : 0);
dest.writeBundle(mSavedFragmentState);
}
@@ -460,6 +465,9 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
// If set this fragment is being retained across the current config change.
boolean mRetaining;
+ // If set this fragment's loaders are being retained across the current config change.
+ boolean mRetainLoader;
+
// If set this fragment has menu items to contribute.
boolean mHasMenu;
@@ -2407,7 +2415,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
mLoaderManager = mHost.getLoaderManager(mWho, mLoadersStarted, false);
}
if (mLoaderManager != null) {
- if (mRetaining) {
+ if (mRetainLoader) {
mLoaderManager.doRetain();
} else {
mLoaderManager.doStop();
diff --git a/core/java/android/app/FragmentController.java b/core/java/android/app/FragmentController.java
index 28dadfa78b32..1b45137fb7c9 100644
--- a/core/java/android/app/FragmentController.java
+++ b/core/java/android/app/FragmentController.java
@@ -341,6 +341,7 @@ public class FragmentController {
*/
public void doLoaderStop(boolean retain) {
mHost.doLoaderStop(retain);
+ mHost.mFragmentManager.setRetainLoader(retain);
}
/**
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 132ffef861e6..51d613247c87 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -869,6 +869,17 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
}
}
+ void setRetainLoader(boolean retain) {
+ if (mActive != null) {
+ for (int i=0; i<mActive.size(); i++) {
+ Fragment f = mActive.get(i);
+ if (f != null) {
+ f.mRetainLoader = retain;
+ }
+ }
+ }
+ }
+
void moveToState(Fragment f, int newState, int transit, int transitionStyle,
boolean keepActive) {
if (DEBUG && false) Log.v(TAG, "moveToState: " + f
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 66fa79639256..478fdd14e093 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -140,6 +140,8 @@ public interface IActivityManager extends IInterface {
public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) throws RemoteException;
public void moveTaskBackwards(int task) throws RemoteException;
public void moveTaskToStack(int taskId, int stackId, boolean toTop) throws RemoteException;
+ public void moveTaskToDockedStack(int taskId, int createMode, boolean toTop)
+ throws RemoteException;
public void resizeStack(int stackId, Rect bounds) throws RemoteException;
public void positionTaskInStack(int taskId, int stackId, int position) throws RemoteException;
public List<StackInfo> getAllStackInfos() throws RemoteException;
@@ -489,7 +491,7 @@ public interface IActivityManager extends IInterface {
public void setTaskDescription(IBinder token, ActivityManager.TaskDescription values)
throws RemoteException;
public void setTaskResizeable(int taskId, boolean resizeable) throws RemoteException;
- public void resizeTask(int taskId, Rect bounds) throws RemoteException;
+ public void resizeTask(int taskId, Rect bounds, int resizeMode) throws RemoteException;
public Rect getTaskBounds(int taskId) throws RemoteException;
public Bitmap getTaskDescriptionIcon(String filename) throws RemoteException;
@@ -533,6 +535,8 @@ public interface IActivityManager extends IInterface {
public int getActivityStackId(IBinder token) throws RemoteException;
public void moveActivityToStack(IBinder token, int stackId) throws RemoteException;
+ public void suppressResizeConfigChanges(boolean suppress) throws RemoteException;
+
/*
* Private non-Binder interfaces
*/
@@ -888,4 +892,6 @@ public interface IActivityManager extends IInterface {
int GET_ACTIVITY_STACK_ID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 343;
int MOVE_ACTIVITY_TO_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 344;
int REPORT_SIZE_CONFIGURATIONS = IBinder.FIRST_CALL_TRANSACTION + 345;
+ int MOVE_TASK_TO_DOCKED_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 346;
+ int SUPPRESS_RESIZE_CONFIG_CHANGES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 347;
}
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index dc8f53d94b4e..2d78e19750ae 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -65,7 +65,8 @@ public interface IApplicationThread extends IInterface {
boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) throws RemoteException;
void scheduleRelaunchActivity(IBinder token, List<ResultInfo> pendingResults,
List<ReferrerIntent> pendingNewIntents, int configChanges, boolean notResumed,
- Configuration config, Configuration overrideConfig) throws RemoteException;
+ Configuration config, Configuration overrideConfig, boolean preserveWindow)
+ throws RemoteException;
void scheduleNewIntent(List<ReferrerIntent> intent, IBinder token) throws RemoteException;
void scheduleDestroyActivity(IBinder token, boolean finished,
int configChanges) throws RemoteException;
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index dee8d2115863..718433719d0d 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1044,7 +1044,7 @@ public class Instrumentation {
activity.attach(context, aThread, this, token, 0, application, intent,
info, title, parent, id,
(Activity.NonConfigurationInstances)lastNonConfigurationInstance,
- new Configuration(), null, null);
+ new Configuration(), null, null, null);
return activity;
}
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/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 3d264c6f2cba..288a2cb5fa4f 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -240,7 +240,7 @@ final class SystemServiceRegistry {
new CachedServiceFetcher<DevicePolicyManager>() {
@Override
public DevicePolicyManager createService(ContextImpl ctx) {
- return DevicePolicyManager.create(ctx, ctx.mMainThread.getHandler());
+ return DevicePolicyManager.create(ctx);
}});
registerService(Context.DOWNLOAD_SERVICE, DownloadManager.class,
diff --git a/core/java/android/app/admin/DeviceAdminInfo.java b/core/java/android/app/admin/DeviceAdminInfo.java
index d1e40ae9bd5e..4e9adf09c351 100644
--- a/core/java/android/app/admin/DeviceAdminInfo.java
+++ b/core/java/android/app/admin/DeviceAdminInfo.java
@@ -20,6 +20,7 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
+import android.annotation.NonNull;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ActivityInfo;
@@ -360,6 +361,7 @@ public final class DeviceAdminInfo implements Parcelable {
/**
* Return the component of the receiver that implements this device admin.
*/
+ @NonNull
public ComponentName getComponent() {
return new ComponentName(mReceiver.activityInfo.packageName,
mReceiver.activityInfo.name);
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index ac50699ca110..e6484e965ee0 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -32,7 +32,6 @@ import android.content.pm.ResolveInfo;
import android.graphics.Bitmap;
import android.net.ProxyInfo;
import android.os.Bundle;
-import android.os.Handler;
import android.os.PersistableBundle;
import android.os.Process;
import android.os.RemoteCallback;
@@ -45,6 +44,7 @@ import android.security.Credentials;
import android.service.restrictions.RestrictionsReceiver;
import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.org.conscrypt.TrustedCertificateStore;
import org.xmlpull.v1.XmlPullParserException;
@@ -87,18 +87,30 @@ public class DevicePolicyManager {
private final Context mContext;
private final IDevicePolicyManager mService;
- private DevicePolicyManager(Context context, Handler handler) {
+ private DevicePolicyManager(Context context) {
+ this(context, IDevicePolicyManager.Stub.asInterface(
+ ServiceManager.getService(Context.DEVICE_POLICY_SERVICE)));
+ }
+
+ /** @hide */
+ @VisibleForTesting
+ protected DevicePolicyManager(Context context, IDevicePolicyManager service) {
mContext = context;
- mService = IDevicePolicyManager.Stub.asInterface(
- ServiceManager.getService(Context.DEVICE_POLICY_SERVICE));
+ mService = service;
}
/** @hide */
- public static DevicePolicyManager create(Context context, Handler handler) {
- DevicePolicyManager me = new DevicePolicyManager(context, handler);
+ public static DevicePolicyManager create(Context context) {
+ DevicePolicyManager me = new DevicePolicyManager(context);
return me.mService != null ? me : null;
}
+ /** @hide test will override it. */
+ @VisibleForTesting
+ protected int myUserId() {
+ return UserHandle.myUserId();
+ }
+
/**
* Activity action: Starts the provisioning flow which sets up a managed profile.
*
@@ -823,7 +835,7 @@ public class DevicePolicyManager {
* active (enabled) in the system.
*/
public boolean isAdminActive(@NonNull ComponentName admin) {
- return isAdminActiveAsUser(admin, UserHandle.myUserId());
+ return isAdminActiveAsUser(admin, myUserId());
}
/**
@@ -863,7 +875,7 @@ public class DevicePolicyManager {
* returned.
*/
public List<ComponentName> getActiveAdmins() {
- return getActiveAdminsAsUser(UserHandle.myUserId());
+ return getActiveAdminsAsUser(myUserId());
}
/**
@@ -889,7 +901,7 @@ public class DevicePolicyManager {
public boolean packageHasActiveAdmins(String packageName) {
if (mService != null) {
try {
- return mService.packageHasActiveAdmins(packageName, UserHandle.myUserId());
+ return mService.packageHasActiveAdmins(packageName, myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -906,7 +918,7 @@ public class DevicePolicyManager {
public void removeActiveAdmin(@NonNull ComponentName admin) {
if (mService != null) {
try {
- mService.removeActiveAdmin(admin, UserHandle.myUserId());
+ mService.removeActiveAdmin(admin, myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -925,7 +937,7 @@ public class DevicePolicyManager {
public boolean hasGrantedPolicy(@NonNull ComponentName admin, int usesPolicy) {
if (mService != null) {
try {
- return mService.hasGrantedPolicy(admin, usesPolicy, UserHandle.myUserId());
+ return mService.hasGrantedPolicy(admin, usesPolicy, myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -1040,7 +1052,7 @@ public class DevicePolicyManager {
* all admins.
*/
public int getPasswordQuality(@Nullable ComponentName admin) {
- return getPasswordQuality(admin, UserHandle.myUserId());
+ return getPasswordQuality(admin, myUserId());
}
/** @hide per-user version */
@@ -1093,7 +1105,7 @@ public class DevicePolicyManager {
* all admins.
*/
public int getPasswordMinimumLength(@Nullable ComponentName admin) {
- return getPasswordMinimumLength(admin, UserHandle.myUserId());
+ return getPasswordMinimumLength(admin, myUserId());
}
/** @hide per-user version */
@@ -1154,7 +1166,7 @@ public class DevicePolicyManager {
* password.
*/
public int getPasswordMinimumUpperCase(@Nullable ComponentName admin) {
- return getPasswordMinimumUpperCase(admin, UserHandle.myUserId());
+ return getPasswordMinimumUpperCase(admin, myUserId());
}
/** @hide per-user version */
@@ -1215,7 +1227,7 @@ public class DevicePolicyManager {
* password.
*/
public int getPasswordMinimumLowerCase(@Nullable ComponentName admin) {
- return getPasswordMinimumLowerCase(admin, UserHandle.myUserId());
+ return getPasswordMinimumLowerCase(admin, myUserId());
}
/** @hide per-user version */
@@ -1273,7 +1285,7 @@ public class DevicePolicyManager {
* @return The minimum number of letters required in the password.
*/
public int getPasswordMinimumLetters(@Nullable ComponentName admin) {
- return getPasswordMinimumLetters(admin, UserHandle.myUserId());
+ return getPasswordMinimumLetters(admin, myUserId());
}
/** @hide per-user version */
@@ -1332,7 +1344,7 @@ public class DevicePolicyManager {
* @return The minimum number of numerical digits required in the password.
*/
public int getPasswordMinimumNumeric(@Nullable ComponentName admin) {
- return getPasswordMinimumNumeric(admin, UserHandle.myUserId());
+ return getPasswordMinimumNumeric(admin, myUserId());
}
/** @hide per-user version */
@@ -1390,7 +1402,7 @@ public class DevicePolicyManager {
* @return The minimum number of symbols required in the password.
*/
public int getPasswordMinimumSymbols(@Nullable ComponentName admin) {
- return getPasswordMinimumSymbols(admin, UserHandle.myUserId());
+ return getPasswordMinimumSymbols(admin, myUserId());
}
/** @hide per-user version */
@@ -1449,7 +1461,7 @@ public class DevicePolicyManager {
* @return The minimum number of letters required in the password.
*/
public int getPasswordMinimumNonLetter(@Nullable ComponentName admin) {
- return getPasswordMinimumNonLetter(admin, UserHandle.myUserId());
+ return getPasswordMinimumNonLetter(admin, myUserId());
}
/** @hide per-user version */
@@ -1540,7 +1552,7 @@ public class DevicePolicyManager {
public long getPasswordExpirationTimeout(@Nullable ComponentName admin) {
if (mService != null) {
try {
- return mService.getPasswordExpirationTimeout(admin, UserHandle.myUserId());
+ return mService.getPasswordExpirationTimeout(admin, myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -1561,7 +1573,7 @@ public class DevicePolicyManager {
public long getPasswordExpiration(@Nullable ComponentName admin) {
if (mService != null) {
try {
- return mService.getPasswordExpiration(admin, UserHandle.myUserId());
+ return mService.getPasswordExpiration(admin, myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -1577,7 +1589,7 @@ public class DevicePolicyManager {
* @return The length of the password history
*/
public int getPasswordHistoryLength(@Nullable ComponentName admin) {
- return getPasswordHistoryLength(admin, UserHandle.myUserId());
+ return getPasswordHistoryLength(admin, myUserId());
}
/** @hide per-user version */
@@ -1617,7 +1629,7 @@ public class DevicePolicyManager {
public boolean isActivePasswordSufficient() {
if (mService != null) {
try {
- return mService.isActivePasswordSufficient(UserHandle.myUserId());
+ return mService.isActivePasswordSufficient(myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -1636,7 +1648,7 @@ public class DevicePolicyManager {
public int getCurrentFailedPasswordAttempts() {
if (mService != null) {
try {
- return mService.getCurrentFailedPasswordAttempts(UserHandle.myUserId());
+ return mService.getCurrentFailedPasswordAttempts(myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -1698,7 +1710,7 @@ public class DevicePolicyManager {
* all admins.
*/
public int getMaximumFailedPasswordsForWipe(@Nullable ComponentName admin) {
- return getMaximumFailedPasswordsForWipe(admin, UserHandle.myUserId());
+ return getMaximumFailedPasswordsForWipe(admin, myUserId());
}
/** @hide per-user version */
@@ -1818,7 +1830,7 @@ public class DevicePolicyManager {
* all admins if admin is null. Returns 0 if there are no restrictions.
*/
public long getMaximumTimeToLock(@Nullable ComponentName admin) {
- return getMaximumTimeToLock(admin, UserHandle.myUserId());
+ return getMaximumTimeToLock(admin, myUserId());
}
/** @hide per-user version */
@@ -1881,7 +1893,7 @@ public class DevicePolicyManager {
public void wipeData(int flags) {
if (mService != null) {
try {
- mService.wipeData(flags, UserHandle.myUserId());
+ mService.wipeData(flags, myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -1995,7 +2007,7 @@ public class DevicePolicyManager {
public ComponentName getGlobalProxyAdmin() {
if (mService != null) {
try {
- return mService.getGlobalProxyAdmin(UserHandle.myUserId());
+ return mService.getGlobalProxyAdmin(myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -2145,7 +2157,7 @@ public class DevicePolicyManager {
public boolean getStorageEncryption(@Nullable ComponentName admin) {
if (mService != null) {
try {
- return mService.getStorageEncryption(admin, UserHandle.myUserId());
+ return mService.getStorageEncryption(admin, myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -2173,7 +2185,7 @@ public class DevicePolicyManager {
* or {@link #ENCRYPTION_STATUS_ACTIVE}.
*/
public int getStorageEncryptionStatus() {
- return getStorageEncryptionStatus(UserHandle.myUserId());
+ return getStorageEncryptionStatus(myUserId());
}
/** @hide per-user version */
@@ -2410,7 +2422,7 @@ public class DevicePolicyManager {
* have disabled the camera
*/
public boolean getCameraDisabled(@Nullable ComponentName admin) {
- return getCameraDisabled(admin, UserHandle.myUserId());
+ return getCameraDisabled(admin, myUserId());
}
/** @hide per-user version */
@@ -2457,7 +2469,7 @@ public class DevicePolicyManager {
* have disabled screen capture.
*/
public boolean getScreenCaptureDisabled(@Nullable ComponentName admin) {
- return getScreenCaptureDisabled(admin, UserHandle.myUserId());
+ return getScreenCaptureDisabled(admin, myUserId());
}
/** @hide per-user version */
@@ -2557,7 +2569,7 @@ public class DevicePolicyManager {
* for a list.
*/
public int getKeyguardDisabledFeatures(@Nullable ComponentName admin) {
- return getKeyguardDisabledFeatures(admin, UserHandle.myUserId());
+ return getKeyguardDisabledFeatures(admin, myUserId());
}
/** @hide per-user version */
@@ -2590,7 +2602,7 @@ public class DevicePolicyManager {
* @hide
*/
public void setActiveAdmin(@NonNull ComponentName policyReceiver, boolean refreshing) {
- setActiveAdmin(policyReceiver, refreshing, UserHandle.myUserId());
+ setActiveAdmin(policyReceiver, refreshing, myUserId());
}
/**
@@ -2627,7 +2639,7 @@ public class DevicePolicyManager {
public void getRemoveWarning(@Nullable ComponentName admin, RemoteCallback result) {
if (mService != null) {
try {
- mService.getRemoveWarning(admin, result, UserHandle.myUserId());
+ mService.getRemoveWarning(admin, result, myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -2956,7 +2968,7 @@ public class DevicePolicyManager {
throws IllegalArgumentException {
if (mService != null) {
try {
- final int myUserId = UserHandle.myUserId();
+ final int myUserId = myUserId();
mService.setActiveAdmin(admin, false, myUserId);
return mService.setProfileOwner(admin, ownerName, myUserId);
} catch (RemoteException re) {
@@ -3301,7 +3313,7 @@ public class DevicePolicyManager {
*/
public List<PersistableBundle> getTrustAgentConfiguration(@Nullable ComponentName admin,
@NonNull ComponentName agent) {
- return getTrustAgentConfiguration(admin, agent, UserHandle.myUserId());
+ return getTrustAgentConfiguration(admin, agent, myUserId());
}
/** @hide per-user version */
@@ -3927,7 +3939,7 @@ public class DevicePolicyManager {
* @see #setAccountManagementDisabled
*/
public String[] getAccountTypesWithManagementDisabled() {
- return getAccountTypesWithManagementDisabledAsUser(UserHandle.myUserId());
+ return getAccountTypesWithManagementDisabledAsUser(myUserId());
}
/**
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index e6590493616b..670ca803a367 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1613,6 +1613,23 @@ public class Intent implements Parcelable, Cloneable {
= "android.intent.action.GET_PERMISSIONS_COUNT";
/**
+ * Broadcast action that requests list of all apps that have runtime permissions. It will
+ * respond to the request by sending a broadcast with action defined by
+ * {@link #EXTRA_GET_PERMISSIONS_PACKAGES_RESPONSE_INTENT}. The response will contain
+ * {@link #EXTRA_GET_PERMISSIONS_APP_LIST_RESULT}, as well as
+ * {@link #EXTRA_GET_PERMISSIONS_APP_LABEL_LIST_RESULT}, with contents described below or
+ * a null upon failure.
+ *
+ * <p>{@link #EXTRA_GET_PERMISSIONS_APP_LIST_RESULT} will contain a list of package names of
+ * apps that have runtime permissions. {@link #EXTRA_GET_PERMISSIONS_APP_LABEL_LIST_RESULT}
+ * will contain the list of app labels corresponding ot the apps in the first list.
+ *
+ * @hide
+ */
+ public static final String ACTION_GET_PERMISSIONS_PACKAGES
+ = "android.intent.action.GET_PERMISSIONS_PACKAGES";
+
+ /**
* Extra included in response to {@link #ACTION_GET_PERMISSIONS_COUNT}.
* @hide
*/
@@ -1627,6 +1644,20 @@ public class Intent implements Parcelable, Cloneable {
= "android.intent.extra.GET_PERMISSIONS_GROUP_LIST_RESULT";
/**
+ * String list of apps that have one or more runtime permissions.
+ * @hide
+ */
+ public static final String EXTRA_GET_PERMISSIONS_APP_LIST_RESULT
+ = "android.intent.extra.GET_PERMISSIONS_APP_LIST_RESULT";
+
+ /**
+ * String list of app labels for apps that have one or more runtime permissions.
+ * @hide
+ */
+ public static final String EXTRA_GET_PERMISSIONS_APP_LABEL_LIST_RESULT
+ = "android.intent.extra.GET_PERMISSIONS_APP_LABEL_LIST_RESULT";
+
+ /**
* Required extra to be sent with {@link #ACTION_GET_PERMISSIONS_COUNT} broadcasts.
* @hide
*/
@@ -1634,6 +1665,13 @@ public class Intent implements Parcelable, Cloneable {
= "android.intent.extra.GET_PERMISSIONS_RESONSE_INTENT";
/**
+ * Required extra to be sent with {@link #ACTION_GET_PERMISSIONS_PACKAGES} broadcasts.
+ * @hide
+ */
+ public static final String EXTRA_GET_PERMISSIONS_PACKAGES_RESPONSE_INTENT
+ = "android.intent.extra.GET_PERMISSIONS_PACKAGES_RESONSE_INTENT";
+
+ /**
* Activity action: Launch UI to manage which apps have a given permission.
* <p>
* Input: {@link #EXTRA_PERMISSION_NAME} specifies the permission access
@@ -2995,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/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index a59f429bfabc..a121b4d312fd 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -33,12 +33,16 @@ import java.lang.annotation.RetentionPolicy;
*/
public class ActivityInfo extends ComponentInfo
implements Parcelable {
+
+ // NOTE: When adding new data members be sure to update the copy-constructor, Parcel
+ // constructor, and writeToParcel.
+
/**
* A style resource identifier (in the package's resources) of this
* activity's theme. From the "theme" attribute or, if not set, 0.
*/
public int theme;
-
+
/**
* Constant corresponding to <code>standard</code> in
* the {@link android.R.attr#launchMode} attribute.
@@ -707,6 +711,7 @@ public class ActivityInfo extends ComponentInfo
super(orig);
theme = orig.theme;
launchMode = orig.launchMode;
+ documentLaunchMode = orig.documentLaunchMode;
permission = orig.permission;
taskAffinity = orig.taskAffinity;
targetActivity = orig.targetActivity;
@@ -788,6 +793,7 @@ public class ActivityInfo extends ComponentInfo
super.writeToParcel(dest, parcelableFlags);
dest.writeInt(theme);
dest.writeInt(launchMode);
+ dest.writeInt(documentLaunchMode);
dest.writeString(permission);
dest.writeString(taskAffinity);
dest.writeString(targetActivity);
@@ -827,6 +833,7 @@ public class ActivityInfo extends ComponentInfo
super(source);
theme = source.readInt();
launchMode = source.readInt();
+ documentLaunchMode = source.readInt();
permission = source.readString();
taskAffinity = source.readString();
targetActivity = source.readString();
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 968f9b27d629..04b1a3bd2369 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -114,6 +114,12 @@ public class PackageParser {
/** File name in an APK for the Android manifest. */
private static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml";
+ /**
+ * File name in an APK for bytecode. There may be additional bytecode files
+ * but this one is always required for an APK that has code.
+ */
+ private static final String BYTECODE_FILENAME = "classes.dex";
+
/** Path prefix for apps on expanded storage */
private static final String MNT_EXPAND = "/mnt/expand/";
@@ -615,6 +621,7 @@ public class PackageParser {
public final static int PARSE_IS_PRIVILEGED = 1<<7;
public final static int PARSE_COLLECT_CERTIFICATES = 1<<8;
public final static int PARSE_TRUSTED_OVERLAY = 1<<9;
+ public final static int PARSE_ENFORCE_CODE = 1<<10;
private static final Comparator<String> sSplitNameComparator = new SplitNameComparator();
@@ -1066,8 +1073,11 @@ public class PackageParser {
private static void collectCertificates(Package pkg, File apkFile, int flags)
throws PackageParserException {
+ final boolean requireCode = ((flags & PARSE_ENFORCE_CODE) != 0)
+ && ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0);
final String apkPath = apkFile.getAbsolutePath();
+ boolean codeFound = false;
StrictJarFile jarFile = null;
try {
jarFile = new StrictJarFile(apkPath);
@@ -1089,13 +1099,23 @@ public class PackageParser {
final ZipEntry entry = i.next();
if (entry.isDirectory()) continue;
- if (entry.getName().startsWith("META-INF/")) continue;
- if (entry.getName().equals(ANDROID_MANIFEST_FILENAME)) continue;
+
+ final String entryName = entry.getName();
+ if (entryName.startsWith("META-INF/")) continue;
+ if (entryName.equals(ANDROID_MANIFEST_FILENAME)) continue;
+ if (entryName.equals(BYTECODE_FILENAME)) {
+ codeFound = true;
+ }
toVerify.add(entry);
}
}
+ if (!codeFound && requireCode) {
+ throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "Package " + apkPath + " code is missing");
+ }
+
// Verify that entries are signed consistently with the first entry
// we encountered. Note that for splits, certificates may have
// already been populated during an earlier parse of a base APK.
@@ -4561,6 +4581,17 @@ public class PackageParser {
return applicationInfo.isUpdatedSystemApp();
}
+ /**
+ * @hide
+ */
+ public boolean canHaveOatDir() {
+ // The following app types CANNOT have oat directory
+ // - non-updated system apps
+ // - forward-locked apps or apps installed in ASEC containers
+ return (!isSystemApp() || isUpdatedSystemApp())
+ && !isForwardLocked() && !applicationInfo.isExternalAsec();
+ }
+
public String toString() {
return "Package{"
+ Integer.toHexString(System.identityHashCode(this))
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index 73925633f741..d7c221510942 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -136,7 +136,16 @@ public class UserInfo implements Parcelable {
* the method always returns false.
*/
public boolean isSystemOnly() {
- return id == UserHandle.USER_SYSTEM && UserManager.isSplitSystemUser();
+ return isSystemOnly(id);
+ }
+
+ /**
+ * Returns true if the given user is a split system user.
+ * <p>If {@link UserManager#isSplitSystemUser split system user mode} is not enabled,
+ * the method always returns false.
+ */
+ public static boolean isSystemOnly(int userId) {
+ return userId == UserHandle.USER_SYSTEM && UserManager.isSplitSystemUser();
}
/**
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 927c02f9ecfd..477b62cd86fa 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -61,7 +61,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
* resource qualifier. 0 if undefined.
*/
public int mcc;
-
+
/**
* IMSI MNC (Mobile Network Code), corresponding to
* <a href="{@docRoot}guide/topics/resources/providing-resources.html#MccQualifier">mnc</a>
@@ -199,7 +199,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
* @hide
*/
public static final int SCREENLAYOUT_COMPAT_NEEDED = 0x10000000;
-
+
/**
* Bit mask of overall layout of the screen. Currently there are two
* fields:
@@ -207,11 +207,11 @@ public final class Configuration implements Parcelable, Comparable<Configuration
* of the screen. They may be one of
* {@link #SCREENLAYOUT_SIZE_SMALL}, {@link #SCREENLAYOUT_SIZE_NORMAL},
* {@link #SCREENLAYOUT_SIZE_LARGE}, or {@link #SCREENLAYOUT_SIZE_XLARGE}.</p>
- *
+ *
* <p>The {@link #SCREENLAYOUT_LONG_MASK} defines whether the screen
* is wider/taller than normal. They may be one of
* {@link #SCREENLAYOUT_LONG_NO} or {@link #SCREENLAYOUT_LONG_YES}.</p>
- *
+ *
* <p>The {@link #SCREENLAYOUT_LAYOUTDIR_MASK} defines whether the screen layout
* is either LTR or RTL. They may be one of
* {@link #SCREENLAYOUT_LAYOUTDIR_LTR} or {@link #SCREENLAYOUT_LAYOUTDIR_RTL}.</p>
@@ -295,6 +295,62 @@ public final class Configuration implements Parcelable, Comparable<Configuration
return curLayout;
}
+ /** @hide */
+ public static String configurationDiffToString(int diff) {
+ ArrayList<String> list = new ArrayList<>();
+ if ((diff & ActivityInfo.CONFIG_MCC) != 0) {
+ list.add("CONFIG_MCC");
+ }
+ if ((diff & ActivityInfo.CONFIG_MNC) != 0) {
+ list.add("CONFIG_MNC");
+ }
+ if ((diff & ActivityInfo.CONFIG_LOCALE) != 0) {
+ list.add("CONFIG_LOCALE");
+ }
+ if ((diff & ActivityInfo.CONFIG_TOUCHSCREEN) != 0) {
+ list.add("CONFIG_TOUCHSCREEN");
+ }
+ if ((diff & ActivityInfo.CONFIG_KEYBOARD) != 0) {
+ list.add("CONFIG_KEYBOARD");
+ }
+ if ((diff & ActivityInfo.CONFIG_KEYBOARD_HIDDEN) != 0) {
+ list.add("CONFIG_KEYBOARD_HIDDEN");
+ }
+ if ((diff & ActivityInfo.CONFIG_NAVIGATION) != 0) {
+ list.add("CONFIG_NAVIGATION");
+ }
+ if ((diff & ActivityInfo.CONFIG_ORIENTATION) != 0) {
+ list.add("CONFIG_ORIENTATION");
+ }
+ if ((diff & ActivityInfo.CONFIG_SCREEN_LAYOUT) != 0) {
+ list.add("CONFIG_SCREEN_LAYOUT");
+ }
+ if ((diff & ActivityInfo.CONFIG_UI_MODE) != 0) {
+ list.add("CONFIG_UI_MODE");
+ }
+ if ((diff & ActivityInfo.CONFIG_SCREEN_SIZE) != 0) {
+ list.add("CONFIG_SCREEN_SIZE");
+ }
+ if ((diff & ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE) != 0) {
+ list.add("CONFIG_SMALLEST_SCREEN_SIZE");
+ }
+ if ((diff & ActivityInfo.CONFIG_LAYOUT_DIRECTION) != 0) {
+ list.add("CONFIG_LAYOUT_DIRECTION");
+ }
+ if ((diff & ActivityInfo.CONFIG_FONT_SCALE) != 0) {
+ list.add("CONFIG_FONT_SCALE");
+ }
+ StringBuilder builder = new StringBuilder("{");
+ for (int i = 0, n = list.size(); i < n; i++) {
+ builder.append(list.get(i));
+ if (i != n - 1) {
+ builder.append(", ");
+ }
+ }
+ builder.append("}");
+ return builder.toString();
+ }
+
/**
* Check if the Configuration's current {@link #screenLayout} is at
* least the given size.
@@ -323,7 +379,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
* <a href="{@docRoot}guide/topics/resources/providing-resources.html#TouchscreenQualifier">finger</a>
* resource qualifier. */
public static final int TOUCHSCREEN_FINGER = 3;
-
+
/**
* The kind of touch screen attached to the device.
* One of: {@link #TOUCHSCREEN_NOTOUCH}, {@link #TOUCHSCREEN_FINGER}.
@@ -344,7 +400,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
* <a href="{@docRoot}guide/topics/resources/providing-resources.html#ImeQualifier">12key</a>
* resource qualifier. */
public static final int KEYBOARD_12KEY = 3;
-
+
/**
* The kind of keyboard attached to the device.
* One of: {@link #KEYBOARD_NOKEYS}, {@link #KEYBOARD_QWERTY},
@@ -364,7 +420,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
public static final int KEYBOARDHIDDEN_YES = 2;
/** Constant matching actual resource implementation. {@hide} */
public static final int KEYBOARDHIDDEN_SOFT = 3;
-
+
/**
* A flag indicating whether any keyboard is available. Unlike
* {@link #hardKeyboardHidden}, this also takes into account a soft
@@ -373,7 +429,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
* {@link #KEYBOARDHIDDEN_NO}, {@link #KEYBOARDHIDDEN_YES}.
*/
public int keyboardHidden;
-
+
/** Constant for {@link #hardKeyboardHidden}: a value indicating that no value has been set. */
public static final int HARDKEYBOARDHIDDEN_UNDEFINED = 0;
/** Constant for {@link #hardKeyboardHidden}, value corresponding to the
@@ -382,7 +438,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
/** Constant for {@link #hardKeyboardHidden}, value corresponding to the
* physical keyboard being hidden. */
public static final int HARDKEYBOARDHIDDEN_YES = 2;
-
+
/**
* A flag indicating whether the hard keyboard has been hidden. This will
* be set on a device with a mechanism to hide the keyboard from the
@@ -390,7 +446,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
* {@link #HARDKEYBOARDHIDDEN_NO}, {@link #HARDKEYBOARDHIDDEN_YES}.
*/
public int hardKeyboardHidden;
-
+
/** Constant for {@link #navigation}: a value indicating that no value has been set. */
public static final int NAVIGATION_UNDEFINED = 0;
/** Constant for {@link #navigation}, value corresponding to the
@@ -409,14 +465,14 @@ public final class Configuration implements Parcelable, Comparable<Configuration
* <a href="{@docRoot}guide/topics/resources/providing-resources.html#NavigationQualifier">wheel</a>
* resource qualifier. */
public static final int NAVIGATION_WHEEL = 4;
-
+
/**
* The kind of navigation method available on the device.
* One of: {@link #NAVIGATION_NONAV}, {@link #NAVIGATION_DPAD},
* {@link #NAVIGATION_TRACKBALL}, {@link #NAVIGATION_WHEEL}.
*/
public int navigation;
-
+
/** Constant for {@link #navigationHidden}: a value indicating that no value has been set. */
public static final int NAVIGATIONHIDDEN_UNDEFINED = 0;
/** Constant for {@link #navigationHidden}, value corresponding to the
@@ -427,7 +483,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
* <a href="{@docRoot}guide/topics/resources/providing-resources.html#NavAvailQualifier">navhidden</a>
* resource qualifier. */
public static final int NAVIGATIONHIDDEN_YES = 2;
-
+
/**
* A flag indicating whether any 5-way or DPAD navigation available.
* This will be set on a device with a mechanism to hide the navigation
@@ -435,7 +491,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
* {@link #NAVIGATIONHIDDEN_NO}, {@link #NAVIGATIONHIDDEN_YES}.
*/
public int navigationHidden;
-
+
/** Constant for {@link #orientation}: a value indicating that no value has been set. */
public static final int ORIENTATION_UNDEFINED = 0;
/** Constant for {@link #orientation}, value corresponding to the
@@ -448,7 +504,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
public static final int ORIENTATION_LANDSCAPE = 2;
/** @deprecated Not currently supported or used. */
@Deprecated public static final int ORIENTATION_SQUARE = 3;
-
+
/**
* Overall orientation of the screen. May be one of
* {@link #ORIENTATION_LANDSCAPE}, {@link #ORIENTATION_PORTRAIT}.
@@ -692,7 +748,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
compatSmallestScreenWidthDp = o.compatSmallestScreenWidthDp;
seq = o.seq;
}
-
+
public String toString() {
StringBuilder sb = new StringBuilder(128);
sb.append("{");
@@ -861,7 +917,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
@Deprecated public void makeDefault() {
setToDefaults();
}
-
+
/**
* Copy the fields from delta into this Configuration object, keeping
* track of which ones have changed. Any undefined fields in
@@ -1001,7 +1057,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
if (delta.seq != 0) {
seq = delta.seq;
}
-
+
return changed;
}
@@ -1119,12 +1175,12 @@ public final class Configuration implements Parcelable, Comparable<Configuration
/**
* Determine if a new resource needs to be loaded from the bit set of
* configuration changes returned by {@link #updateFrom(Configuration)}.
- *
+ *
* @param configChanges The mask of changes configurations as returned by
* {@link #updateFrom(Configuration)}.
* @param interestingChanges The configuration changes that the resource
* can handled, as given in {@link android.util.TypedValue#changingConfigurations}.
- *
+ *
* @return Return true if the resource needs to be loaded, else false.
*/
public static boolean needNewResources(int configChanges, int interestingChanges) {
@@ -1159,7 +1215,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
}
return diff > 0;
}
-
+
/**
* Parcelable methods
*/
@@ -1236,7 +1292,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
compatSmallestScreenWidthDp = source.readInt();
seq = source.readInt();
}
-
+
public static final Parcelable.Creator<Configuration> CREATOR
= new Parcelable.Creator<Configuration>() {
public Configuration createFromParcel(Parcel source) {
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 21ba7bda493e..121a187b3639 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -359,6 +359,14 @@ public final class DisplayManagerGlobal {
}
}
+ public void requestColorTransform(int displayId, int colorTransformId) {
+ try {
+ mDm.requestColorTransform(displayId, colorTransformId);
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Failed to request color transform.", ex);
+ }
+ }
+
public VirtualDisplay createVirtualDisplay(Context context, MediaProjection projection,
String name, int width, int height, int densityDpi, Surface surface, int flags,
VirtualDisplay.Callback callback, Handler handler) {
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index 4486dd4e0887..8a1abf18602a 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -59,6 +59,9 @@ interface IDisplayManager {
// No permissions required.
WifiDisplayStatus getWifiDisplayStatus();
+ // Requires CONFIGURE_DISPLAY_COLOR_TRANSFORM
+ void requestColorTransform(int displayId, int colorTransformId);
+
// Requires CAPTURE_VIDEO_OUTPUT, CAPTURE_SECURE_VIDEO_OUTPUT, or an appropriate
// MediaProjection token for certain combinations of flags.
int createVirtualDisplay(in IVirtualDisplayCallback callback,
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 7fef5e17c5cb..04caa8fcda38 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -772,10 +772,10 @@ public class FingerprintManager {
if (mRemovalCallback != null) {
int reqFingerId = mRemovalFingerprint.getFingerId();
int reqGroupId = mRemovalFingerprint.getGroupId();
- if (fingerId != reqFingerId) {
+ if (reqFingerId != 0 && fingerId != reqFingerId) {
Log.w(TAG, "Finger id didn't match: " + fingerId + " != " + reqFingerId);
}
- if (fingerId != reqFingerId) {
+ if (groupId != reqGroupId) {
Log.w(TAG, "Group id didn't match: " + groupId + " != " + reqGroupId);
}
mRemovalCallback.onRemovalSucceeded(mRemovalFingerprint);
@@ -962,4 +962,3 @@ public class FingerprintManager {
};
}
-
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 112ae1076aa3..8ab8991c7a42 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -436,9 +436,12 @@ public class InputMethodService extends AbstractInputMethodService {
try {
showWindow(true);
} catch (BadTokenException e) {
- if (DEBUG) Log.v(TAG, "BadTokenException: IME is done.");
- mWindowVisible = false;
- mWindowAdded = false;
+ // We have ignored BadTokenException here since Jelly Bean MR-2 (API Level 18).
+ // We could ignore BadTokenException in InputMethodService#showWindow() instead,
+ // but it may break assumptions for those who override #showWindow() that we can
+ // detect errors in #showWindow() by checking BadTokenException.
+ // TODO: Investigate its feasibility. Update JavaDoc of #showWindow() of
+ // whether it's OK to override #showWindow() or not.
}
}
clearInsetOfPreviousIme();
@@ -1445,7 +1448,19 @@ public class InputMethodService extends AbstractInputMethodService {
mWindowWasVisible = mWindowVisible;
mInShowWindow = true;
showWindowInner(showInput);
+ } catch (BadTokenException e) {
+ // BadTokenException is a normal consequence in certain situations, e.g., swapping IMEs
+ // while there is a DO_SHOW_SOFT_INPUT message in the IIMethodWrapper queue.
+ if (DEBUG) Log.v(TAG, "BadTokenException: IME is done.");
+ mWindowVisible = false;
+ mWindowAdded = false;
+ // Rethrow the exception to preserve the existing behavior. Some IMEs may have directly
+ // called this method and relied on this exception for some clean-up tasks.
+ // TODO: Give developers a clear guideline of whether it's OK to call this method or
+ // InputMethodManager#showSoftInputFromInputMethod() should always be used instead.
+ throw e;
} finally {
+ // TODO: Is it OK to set true when we get BadTokenException?
mWindowWasVisible = true;
mInShowWindow = false;
}
@@ -1456,15 +1471,9 @@ public class InputMethodService extends AbstractInputMethodService {
final int previousImeWindowStatus =
(mWindowVisible ? IME_ACTIVE : 0) | (isInputViewShown() ? IME_VISIBLE : 0);
mWindowVisible = true;
- if (!mShowInputRequested) {
- if (mInputStarted) {
- if (showInput) {
- doShowInput = true;
- mShowInputRequested = true;
- }
- }
- } else {
- showInput = true;
+ if (!mShowInputRequested && mInputStarted && showInput) {
+ doShowInput = true;
+ mShowInputRequested = true;
}
if (DEBUG) Log.v(TAG, "showWindow: updating UI");
@@ -1985,31 +1994,25 @@ public class InputMethodService extends AbstractInputMethodService {
// We want our own movement method to handle the key, so the
// cursor will properly move in our own word wrapping.
if (count == MOVEMENT_DOWN) {
- if (movement.onKeyDown(eet,
- (Spannable)eet.getText(), keyCode, event)) {
+ if (movement.onKeyDown(eet, eet.getText(), keyCode, event)) {
reportExtractedMovement(keyCode, 1);
return true;
}
} else if (count == MOVEMENT_UP) {
- if (movement.onKeyUp(eet,
- (Spannable)eet.getText(), keyCode, event)) {
+ if (movement.onKeyUp(eet, eet.getText(), keyCode, event)) {
return true;
}
} else {
- if (movement.onKeyOther(eet, (Spannable)eet.getText(), event)) {
+ if (movement.onKeyOther(eet, eet.getText(), event)) {
reportExtractedMovement(keyCode, count);
} else {
KeyEvent down = KeyEvent.changeAction(event, KeyEvent.ACTION_DOWN);
- if (movement.onKeyDown(eet,
- (Spannable)eet.getText(), keyCode, down)) {
+ if (movement.onKeyDown(eet, eet.getText(), keyCode, down)) {
KeyEvent up = KeyEvent.changeAction(event, KeyEvent.ACTION_UP);
- movement.onKeyUp(eet,
- (Spannable)eet.getText(), keyCode, up);
+ movement.onKeyUp(eet, eet.getText(), keyCode, up);
while (--count > 0) {
- movement.onKeyDown(eet,
- (Spannable)eet.getText(), keyCode, down);
- movement.onKeyUp(eet,
- (Spannable)eet.getText(), keyCode, up);
+ movement.onKeyDown(eet, eet.getText(), keyCode, down);
+ movement.onKeyUp(eet, eet.getText(), keyCode, up);
}
reportExtractedMovement(keyCode, count);
}
@@ -2125,7 +2128,7 @@ public class InputMethodService extends AbstractInputMethodService {
} else {
InputConnection ic = getCurrentInputConnection();
if (ic != null) {
- ic.commitText(String.valueOf((char) charCode), 1);
+ ic.commitText(String.valueOf(charCode), 1);
}
}
break;
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 9a2a24128b92..444548faad42 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -208,6 +208,12 @@ public class ConnectivityManager {
* {@link android.content.Intent#getParcelableExtra(String)}.
*/
public static final String EXTRA_CAPTIVE_PORTAL = "android.net.extra.CAPTIVE_PORTAL";
+
+ /**
+ * Key for passing a URL to the captive portal login activity.
+ */
+ public static final String EXTRA_CAPTIVE_PORTAL_URL = "android.net.extra.CAPTIVE_PORTAL_URL";
+
/**
* Broadcast action to indicate the change of data activity status
* (idle or active) on a network in a recent period.
diff --git a/core/java/android/net/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java
index a939ccee4ca7..3f36d65e577c 100644
--- a/core/java/android/net/NetworkScoreManager.java
+++ b/core/java/android/net/NetworkScoreManager.java
@@ -245,7 +245,8 @@ public class NetworkScoreManager {
intent.putExtra(EXTRA_NETWORKS_TO_SCORE, networks);
// A scorer should never become active if its package doesn't hold SCORE_NETWORKS, but
// ensure the package still holds it to be extra safe.
- mContext.sendBroadcastAsUser(intent, UserHandle.OWNER, Manifest.permission.SCORE_NETWORKS);
+ // TODO: http://b/23422763
+ mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM, Manifest.permission.SCORE_NETWORKS);
return true;
}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index bad94fce20aa..8e86a53072e7 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -463,13 +463,15 @@ public abstract class BatteryStats implements Parcelable {
public abstract long getCpuPowerMaUs(int which);
/**
- * Returns the approximate cpu time (in milliseconds) spent at a certain CPU speed.
+ * Returns the approximate cpu time (in milliseconds) spent at a certain CPU speed for a
+ * given CPU cluster.
+ * @param cluster the index of the CPU cluster.
* @param step the index of the CPU speed. This is not the actual speed of the CPU.
* @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
- * @see BatteryStats#getCpuSpeedSteps()
+ * @see PowerProfile.getNumCpuClusters()
+ * @see PowerProfile.getNumSpeedStepsInCpuCluster(int)
*/
- @Deprecated
- public abstract long getTimeAtCpuSpeed(int step, int which);
+ public abstract long getTimeAtCpuSpeed(int cluster, int step, int which);
public static abstract class Sensor {
/*
@@ -2276,9 +2278,6 @@ public abstract class BatteryStats implements Parcelable {
public abstract Map<String, ? extends Timer> getKernelWakelockStats();
- /** Returns the number of different speeds that the CPU can run at */
- public abstract int getCpuSpeedSteps();
-
public abstract void writeToParcelWithoutUids(Parcel out, int flags);
private final static void formatTimeRaw(StringBuilder out, long seconds) {
diff --git a/core/java/android/os/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java
index 70cff00636ac..b6d0fcb448f5 100644
--- a/core/java/android/os/PowerManagerInternal.java
+++ b/core/java/android/os/PowerManagerInternal.java
@@ -53,6 +53,15 @@ public abstract class PowerManagerInternal {
*/
public static final int WAKEFULNESS_DOZING = 3;
+
+ /**
+ * Power hint: The user is interacting with the device. The corresponding data field must be
+ * the expected duration of the fling, or 0 if unknown.
+ *
+ * This must be kept in sync with the values in hardware/libhardware/include/hardware/power.h
+ */
+ public static final int POWER_HINT_INTERACTION = 2;
+
public static String wakefulnessToString(int wakefulness) {
switch (wakefulness) {
case WAKEFULNESS_ASLEEP:
@@ -148,4 +157,6 @@ public abstract class PowerManagerInternal {
public abstract void updateUidProcState(int uid, int procState);
public abstract void uidGone(int uid);
+
+ public abstract void powerHint(int hintId, int data);
}
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 8c544f44f244..41de579201a5 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -410,7 +410,7 @@ public class RecoverySystem {
Intent intent = new Intent("android.intent.action.MASTER_CLEAR_NOTIFICATION");
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
- context.sendOrderedBroadcastAsUser(intent, UserHandle.OWNER,
+ context.sendOrderedBroadcastAsUser(intent, UserHandle.SYSTEM,
android.Manifest.permission.MASTER_CLEAR,
new BroadcastReceiver() {
@Override
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 87ce12cbe37c..8b2c74f07598 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -1923,7 +1923,7 @@ public final class StrictMode {
if (LOG_V) Log.d(TAG, "strict mode violation stacks read from binder call. i=" + i);
ViolationInfo info = new ViolationInfo(p, !currentlyGathering);
if (info.crashInfo.stackTrace != null && info.crashInfo.stackTrace.length() > 30000) {
- String front = info.crashInfo.stackTrace.substring(256);
+ String front = info.crashInfo.stackTrace.substring(0, 256);
// 30000 characters is way too large for this to be any sane kind of
// strict mode collection of stacks. We've had a problem where we leave
// strict mode violations associated with the thread, and it keeps tacking
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index 48ede4f01585..213e0831c0f2 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -57,15 +57,15 @@ public final class UserHandle implements Parcelable {
/**
* @hide A user id constant to indicate the "owner" user of the device
- * @deprecated Consider using either USER_SYSTEM constant or
- * UserInfo.isPrimary().
+ * @deprecated Consider using either {@link UserHandle#USER_SYSTEM} constant or
+ * check the target user's flag {@link android.content.pm.UserInfo#isAdmin}.
*/
public static final int USER_OWNER = 0;
/**
* @hide A user handle to indicate the primary/owner user of the device
- * @deprecated Consider using either SYSTEM constant or
- * UserInfo.isPrimary().
+ * @deprecated Consider using either {@link UserHandle#SYSTEM} constant or
+ * check the target user's flag {@link android.content.pm.UserInfo#isAdmin}.
*/
public static final UserHandle OWNER = new UserHandle(USER_OWNER);
@@ -90,7 +90,7 @@ public final class UserHandle implements Parcelable {
* user.
* @hide
*/
- public static final boolean isSameUser(int uid1, int uid2) {
+ public static boolean isSameUser(int uid1, int uid2) {
return getUserId(uid1) == getUserId(uid2);
}
@@ -102,12 +102,12 @@ public final class UserHandle implements Parcelable {
* @return whether the appId is the same for both uids
* @hide
*/
- public static final boolean isSameApp(int uid1, int uid2) {
+ public static boolean isSameApp(int uid1, int uid2) {
return getAppId(uid1) == getAppId(uid2);
}
/** @hide */
- public static final boolean isIsolated(int uid) {
+ public static boolean isIsolated(int uid) {
if (uid > 0) {
final int appId = getAppId(uid);
return appId >= Process.FIRST_ISOLATED_UID && appId <= Process.LAST_ISOLATED_UID;
@@ -130,7 +130,7 @@ public final class UserHandle implements Parcelable {
* Returns the user id for a given uid.
* @hide
*/
- public static final int getUserId(int uid) {
+ public static int getUserId(int uid) {
if (MU_ENABLED) {
return uid / PER_USER_RANGE;
} else {
@@ -139,12 +139,12 @@ public final class UserHandle implements Parcelable {
}
/** @hide */
- public static final int getCallingUserId() {
+ public static int getCallingUserId() {
return getUserId(Binder.getCallingUid());
}
/** @hide */
- public static final UserHandle getCallingUserHandle() {
+ public static UserHandle getCallingUserHandle() {
int userId = getUserId(Binder.getCallingUid());
UserHandle userHandle = userHandles.get(userId);
// Intentionally not synchronized to save time
@@ -159,7 +159,7 @@ public final class UserHandle implements Parcelable {
* Returns the uid that is composed from the userId and the appId.
* @hide
*/
- public static final int getUid(int userId, int appId) {
+ public static int getUid(int userId, int appId) {
if (MU_ENABLED) {
return userId * PER_USER_RANGE + (appId % PER_USER_RANGE);
} else {
@@ -171,7 +171,7 @@ public final class UserHandle implements Parcelable {
* Returns the app id (or base uid) for a given uid, stripping out the user id from it.
* @hide
*/
- public static final int getAppId(int uid) {
+ public static int getAppId(int uid) {
return uid % PER_USER_RANGE;
}
@@ -179,7 +179,7 @@ public final class UserHandle implements Parcelable {
* Returns the gid shared between all apps with this userId.
* @hide
*/
- public static final int getUserGid(int userId) {
+ public static int getUserGid(int userId) {
return getUid(userId, Process.SHARED_USER_GID);
}
@@ -187,7 +187,7 @@ public final class UserHandle implements Parcelable {
* Returns the shared app gid for a given uid or appId.
* @hide
*/
- public static final int getSharedAppGid(int id) {
+ public static int getSharedAppGid(int id) {
return Process.FIRST_SHARED_APPLICATION_GID + (id % PER_USER_RANGE)
- Process.FIRST_APPLICATION_UID;
}
@@ -196,7 +196,7 @@ public final class UserHandle implements Parcelable {
* Returns the app id for a given shared app gid. Returns -1 if the ID is invalid.
* @hide
*/
- public static final int getAppIdFromSharedAppGid(int gid) {
+ public static int getAppIdFromSharedAppGid(int gid) {
final int appId = getAppId(gid) + Process.FIRST_APPLICATION_UID
- Process.FIRST_SHARED_APPLICATION_GID;
if (appId < 0 || appId >= Process.FIRST_SHARED_APPLICATION_GID) {
@@ -272,7 +272,7 @@ public final class UserHandle implements Parcelable {
* @hide
*/
@SystemApi
- public static final int myUserId() {
+ public static int myUserId() {
return getUserId(Process.myUid());
}
@@ -280,9 +280,10 @@ public final class UserHandle implements Parcelable {
* Returns true if this UserHandle refers to the owner user; false otherwise.
* @return true if this UserHandle refers to the owner user; false otherwise.
* @hide
+ * TODO: find an alternative to this Api.
*/
@SystemApi
- public final boolean isOwner() {
+ public boolean isOwner() {
return this.equals(OWNER);
}
diff --git a/core/java/android/os/storage/VolumeInfo.java b/core/java/android/os/storage/VolumeInfo.java
index 688859479713..c368e5a24a1b 100644
--- a/core/java/android/os/storage/VolumeInfo.java
+++ b/core/java/android/os/storage/VolumeInfo.java
@@ -438,6 +438,8 @@ public class VolumeInfo implements Parcelable {
final Intent intent = new Intent(DocumentsContract.ACTION_BROWSE_DOCUMENT_ROOT);
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.setData(uri);
+ intent.putExtra(DocumentsContract.EXTRA_SHOW_FILESIZE, true);
+ intent.putExtra(DocumentsContract.EXTRA_SHOW_ADVANCED, true);
return intent;
}
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 59609f94546a..1a83cd567dc0 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -93,6 +93,9 @@ public final class DocumentsContract {
public static final String EXTRA_SHOW_ADVANCED = "android.content.extra.SHOW_ADVANCED";
/** {@hide} */
+ public static final String EXTRA_SHOW_FILESIZE = "android.content.extra.SHOW_FILESIZE";
+
+ /** {@hide} */
public static final String EXTRA_TARGET_URI = "android.content.extra.TARGET_URI";
/**
@@ -266,7 +269,7 @@ public final class DocumentsContract {
* writability of a document may change over time, for example due to
* remote access changes. This flag indicates that a document client can
* expect {@link ContentResolver#openOutputStream(Uri)} to succeed.
- *
+ *
* @see #COLUMN_FLAGS
*/
public static final int FLAG_SUPPORTS_WRITE = 1 << 1;
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index a038b0d30887..225f0cf97c2e 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3283,7 +3283,6 @@ public final class Settings {
DOCK_SOUNDS_ENABLED, // moved to global
LOCKSCREEN_SOUNDS_ENABLED,
SHOW_WEB_SUGGESTIONS,
- NOTIFICATION_LIGHT_PULSE,
SIP_CALL_OPTIONS,
SIP_RECEIVE_CALLS,
POINTER_SPEED,
@@ -4921,7 +4920,26 @@ public final class Settings {
"accessibility_display_daltonizer";
/**
- * The timout for considering a press to be a long press in milliseconds.
+ * Setting that specifies whether automatic click when the mouse pointer stops moving is
+ * enabled.
+ *
+ * @hide
+ */
+ public static final String ACCESSIBILITY_AUTOCLICK_ENABLED =
+ "accessibility_autoclick_enabled";
+
+ /**
+ * Integer setting specifying amount of time in ms the mouse pointer has to stay still
+ * before performing click when {@link #ACCESSIBILITY_AUTOCLICK_ENABLED} is set.
+ *
+ * @see #ACCESSIBILITY_AUTOCLICK_ENABLED
+ * @hide
+ */
+ public static final String ACCESSIBILITY_AUTOCLICK_DELAY =
+ "accessibility_autoclick_delay";
+
+ /**
+ * The timeout for considering a press to be a long press in milliseconds.
* @hide
*/
public static final String LONG_PRESS_TIMEOUT = "long_press_timeout";
@@ -5785,6 +5803,8 @@ public final class Settings {
SLEEP_TIMEOUT,
DOUBLE_TAP_TO_WAKE,
CAMERA_GESTURE_DISABLED,
+ ACCESSIBILITY_AUTOCLICK_ENABLED,
+ ACCESSIBILITY_AUTOCLICK_DELAY
};
/**
diff --git a/core/java/android/util/PathParser.java b/core/java/android/util/PathParser.java
index 18dc26279f6c..954dcfbe9b2d 100644
--- a/core/java/android/util/PathParser.java
+++ b/core/java/android/util/PathParser.java
@@ -364,18 +364,32 @@ public class PathParser {
for (int k = 0; k < val.length; k += incr) {
switch (cmd) {
case 'm': // moveto - Start a new sub-path (relative)
- path.rMoveTo(val[k + 0], val[k + 1]);
currentX += val[k + 0];
currentY += val[k + 1];
- currentSegmentStartX = currentX;
- currentSegmentStartY = currentY;
+ if (k > 0) {
+ // According to the spec, if a moveto is followed by multiple
+ // pairs of coordinates, the subsequent pairs are treated as
+ // implicit lineto commands.
+ path.rLineTo(val[k + 0], val[k + 1]);
+ } else {
+ path.rMoveTo(val[k + 0], val[k + 1]);
+ currentSegmentStartX = currentX;
+ currentSegmentStartY = currentY;
+ }
break;
case 'M': // moveto - Start a new sub-path
- path.moveTo(val[k + 0], val[k + 1]);
currentX = val[k + 0];
currentY = val[k + 1];
- currentSegmentStartX = currentX;
- currentSegmentStartY = currentY;
+ if (k > 0) {
+ // According to the spec, if a moveto is followed by multiple
+ // pairs of coordinates, the subsequent pairs are treated as
+ // implicit lineto commands.
+ path.lineTo(val[k + 0], val[k + 1]);
+ } else {
+ path.moveTo(val[k + 0], val[k + 1]);
+ currentSegmentStartX = currentX;
+ currentSegmentStartY = currentY;
+ }
break;
case 'l': // lineto - Draw a line from the current point (relative)
path.rLineTo(val[k + 0], val[k + 1]);
diff --git a/core/java/android/view/BatchedInputEventReceiver.java b/core/java/android/view/BatchedInputEventReceiver.java
new file mode 100644
index 000000000000..b1d28e000bc8
--- /dev/null
+++ b/core/java/android/view/BatchedInputEventReceiver.java
@@ -0,0 +1,82 @@
+/*
+ * 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.os.Looper;
+
+/**
+ * Similar to {@link InputEventReceiver}, but batches events to vsync boundaries when possible.
+ * @hide
+ */
+public class BatchedInputEventReceiver extends InputEventReceiver {
+ Choreographer mChoreographer;
+ private boolean mBatchedInputScheduled;
+
+ public BatchedInputEventReceiver(
+ InputChannel inputChannel, Looper looper, Choreographer choreographer) {
+ super(inputChannel, looper);
+ mChoreographer = choreographer;
+ }
+
+ @Override
+ public void onBatchedInputEventPending() {
+ scheduleBatchedInput();
+ }
+
+ @Override
+ public void dispose() {
+ unscheduleBatchedInput();
+ super.dispose();
+ }
+
+ void doConsumeBatchedInput(long frameTimeNanos) {
+ if (mBatchedInputScheduled) {
+ mBatchedInputScheduled = false;
+ if (consumeBatchedInputEvents(frameTimeNanos) && frameTimeNanos != -1) {
+ // If we consumed a batch here, we want to go ahead and schedule the
+ // consumption of batched input events on the next frame. Otherwise, we would
+ // wait until we have more input events pending and might get starved by other
+ // things occurring in the process. If the frame time is -1, however, then
+ // we're in a non-batching mode, so there's no need to schedule this.
+ scheduleBatchedInput();
+ }
+ }
+ }
+
+ private void scheduleBatchedInput() {
+ if (!mBatchedInputScheduled) {
+ mBatchedInputScheduled = true;
+ mChoreographer.postCallback(Choreographer.CALLBACK_INPUT, mBatchedInputRunnable, null);
+ }
+ }
+
+ private void unscheduleBatchedInput() {
+ if (mBatchedInputScheduled) {
+ mBatchedInputScheduled = false;
+ mChoreographer.removeCallbacks(
+ Choreographer.CALLBACK_INPUT, mBatchedInputRunnable, null);
+ }
+ }
+
+ private final class BatchedInputRunnable implements Runnable {
+ @Override
+ public void run() {
+ doConsumeBatchedInput(mChoreographer.getFrameTimeNanos());
+ }
+ }
+ private final BatchedInputRunnable mBatchedInputRunnable = new BatchedInputRunnable();
+}
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 35c41928f214..1269ad93d306 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -16,7 +16,10 @@
package android.view;
+import android.annotation.RequiresPermission;
+import android.content.Context;
import android.content.res.CompatibilityInfo;
+import android.content.res.Resources;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
@@ -30,6 +33,8 @@ import android.util.Log;
import java.util.Arrays;
+import static android.Manifest.permission.CONFIGURE_DISPLAY_COLOR_TRANSFORM;
+
/**
* Provides information about the size and density of a logical display.
* <p>
@@ -679,6 +684,49 @@ public final class Display {
}
/**
+ * Request the display applies a color transform.
+ * @hide
+ */
+ @RequiresPermission(CONFIGURE_DISPLAY_COLOR_TRANSFORM)
+ public void requestColorTransform(ColorTransform colorTransform) {
+ mGlobal.requestColorTransform(mDisplayId, colorTransform.getId());
+ }
+
+ /**
+ * Returns the active color transform of this display
+ * @hide
+ */
+ public ColorTransform getColorTransform() {
+ synchronized (this) {
+ updateDisplayInfoLocked();
+ return mDisplayInfo.getColorTransform();
+ }
+ }
+
+ /**
+ * Returns the default color transform of this display
+ * @hide
+ */
+ public ColorTransform getDefaultColorTransform() {
+ synchronized (this) {
+ updateDisplayInfoLocked();
+ return mDisplayInfo.getDefaultColorTransform();
+ }
+ }
+
+ /**
+ * Gets the supported color transforms of this device.
+ * @hide
+ */
+ public ColorTransform[] getSupportedColorTransforms() {
+ synchronized (this) {
+ updateDisplayInfoLocked();
+ ColorTransform[] transforms = mDisplayInfo.supportedColorTransforms;
+ return Arrays.copyOf(transforms, transforms.length);
+ }
+ }
+
+ /**
* Gets the app VSYNC offset, in nanoseconds. This is a positive value indicating
* the phase offset of the VSYNC events provided by Choreographer relative to the
* display refresh. For example, if Choreographer reports that the refresh occurred
@@ -1054,4 +1102,89 @@ public final class Display {
}
};
}
+
+ /**
+ * A color transform supported by a given display.
+ *
+ * @see Display#getSupportedColorTransforms()
+ * @hide
+ */
+ public static final class ColorTransform implements Parcelable {
+ public static final ColorTransform[] EMPTY_ARRAY = new ColorTransform[0];
+
+ private final int mId;
+ private final int mColorTransform;
+
+ public ColorTransform(int id, int colorTransform) {
+ mId = id;
+ mColorTransform = colorTransform;
+ }
+
+ public int getId() {
+ return mId;
+ }
+
+ public int getColorTransform() {
+ return mColorTransform;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (!(other instanceof ColorTransform)) {
+ return false;
+ }
+ ColorTransform that = (ColorTransform) other;
+ return mId == that.mId
+ && mColorTransform == that.mColorTransform;
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 1;
+ hash = hash * 17 + mId;
+ hash = hash * 17 + mColorTransform;
+ return hash;
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder("{")
+ .append("id=").append(mId)
+ .append(", colorTransform=").append(mColorTransform)
+ .append("}")
+ .toString();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ private ColorTransform(Parcel in) {
+ this(in.readInt(), in.readInt());
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int parcelableFlags) {
+ out.writeInt(mId);
+ out.writeInt(mColorTransform);
+ }
+
+ @SuppressWarnings("hiding")
+ public static final Parcelable.Creator<ColorTransform> CREATOR
+ = new Parcelable.Creator<ColorTransform>() {
+ @Override
+ public ColorTransform createFromParcel(Parcel in) {
+ return new ColorTransform(in);
+ }
+
+ @Override
+ public ColorTransform[] newArray(int size) {
+ return new ColorTransform[size];
+ }
+ };
+ }
}
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index cf1799040f5f..ee76274ca5a6 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -169,6 +169,15 @@ public final class DisplayInfo implements Parcelable {
*/
public Display.Mode[] supportedModes = Display.Mode.EMPTY_ARRAY;
+ /** The active color transform. */
+ public int colorTransformId;
+
+ /** The default color transform. */
+ public int defaultColorTransformId;
+
+ /** The list of supported color transforms */
+ public Display.ColorTransform[] supportedColorTransforms = Display.ColorTransform.EMPTY_ARRAY;
+
/**
* The logical display density which is the basis for density-independent
* pixels.
@@ -279,6 +288,8 @@ public final class DisplayInfo implements Parcelable {
&& rotation == other.rotation
&& modeId == other.modeId
&& defaultModeId == other.defaultModeId
+ && colorTransformId == other.colorTransformId
+ && defaultColorTransformId == other.defaultColorTransformId
&& logicalDensityDpi == other.logicalDensityDpi
&& physicalXDpi == other.physicalXDpi
&& physicalYDpi == other.physicalYDpi
@@ -317,6 +328,10 @@ public final class DisplayInfo implements Parcelable {
modeId = other.modeId;
defaultModeId = other.defaultModeId;
supportedModes = Arrays.copyOf(other.supportedModes, other.supportedModes.length);
+ colorTransformId = other.colorTransformId;
+ defaultColorTransformId = other.defaultColorTransformId;
+ supportedColorTransforms = Arrays.copyOf(
+ other.supportedColorTransforms, other.supportedColorTransforms.length);
logicalDensityDpi = other.logicalDensityDpi;
physicalXDpi = other.physicalXDpi;
physicalYDpi = other.physicalYDpi;
@@ -353,6 +368,13 @@ public final class DisplayInfo implements Parcelable {
for (int i = 0; i < nModes; i++) {
supportedModes[i] = Display.Mode.CREATOR.createFromParcel(source);
}
+ colorTransformId = source.readInt();
+ defaultColorTransformId = source.readInt();
+ int nColorTransforms = source.readInt();
+ supportedColorTransforms = new Display.ColorTransform[nColorTransforms];
+ for (int i = 0; i < nColorTransforms; i++) {
+ supportedColorTransforms[i] = Display.ColorTransform.CREATOR.createFromParcel(source);
+ }
logicalDensityDpi = source.readInt();
physicalXDpi = source.readFloat();
physicalYDpi = source.readFloat();
@@ -390,6 +412,12 @@ public final class DisplayInfo implements Parcelable {
for (int i = 0; i < supportedModes.length; i++) {
supportedModes[i].writeToParcel(dest, flags);
}
+ dest.writeInt(colorTransformId);
+ dest.writeInt(defaultColorTransformId);
+ dest.writeInt(supportedColorTransforms.length);
+ for (int i = 0; i < supportedColorTransforms.length; i++) {
+ supportedColorTransforms[i].writeToParcel(dest, flags);
+ }
dest.writeInt(logicalDensityDpi);
dest.writeFloat(physicalXDpi);
dest.writeFloat(physicalYDpi);
@@ -461,6 +489,24 @@ public final class DisplayInfo implements Parcelable {
return result;
}
+ public Display.ColorTransform getColorTransform() {
+ return findColorTransform(colorTransformId);
+ }
+
+ public Display.ColorTransform getDefaultColorTransform() {
+ return findColorTransform(defaultColorTransformId);
+ }
+
+ private Display.ColorTransform findColorTransform(int colorTransformId) {
+ for (int i = 0; i < supportedColorTransforms.length; i++) {
+ Display.ColorTransform colorTransform = supportedColorTransforms[i];
+ if (colorTransform.getId() == colorTransformId) {
+ return colorTransform;
+ }
+ }
+ throw new IllegalStateException("Unable to locate color transform: " + colorTransformId);
+ }
+
public void getAppMetrics(DisplayMetrics outMetrics) {
getAppMetrics(outMetrics, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
}
@@ -562,6 +608,12 @@ public final class DisplayInfo implements Parcelable {
sb.append(defaultModeId);
sb.append(", modes ");
sb.append(Arrays.toString(supportedModes));
+ sb.append(", colorTransformId ");
+ sb.append(colorTransformId);
+ sb.append(", defaultColorTransformId ");
+ sb.append(defaultColorTransformId);
+ sb.append(", supportedColorTransforms ");
+ sb.append(Arrays.toString(supportedColorTransforms));
sb.append(", rotation ");
sb.append(rotation);
sb.append(", density ");
diff --git a/core/java/android/view/DragEvent.java b/core/java/android/view/DragEvent.java
index f559e21f661e..34835f4a8070 100644
--- a/core/java/android/view/DragEvent.java
+++ b/core/java/android/view/DragEvent.java
@@ -128,6 +128,8 @@ public class DragEvent implements Parcelable {
float mX, mY;
ClipDescription mClipDescription;
ClipData mClipData;
+ DropPermissionHolder mDropPermissionHolder;
+
Object mLocalState;
boolean mDragResult;
@@ -253,28 +255,30 @@ public class DragEvent implements Parcelable {
}
private void init(int action, float x, float y, ClipDescription description, ClipData data,
- Object localState, boolean result) {
+ DropPermissionHolder dropPermissionHolder, Object localState, boolean result) {
mAction = action;
mX = x;
mY = y;
mClipDescription = description;
mClipData = data;
+ mDropPermissionHolder = dropPermissionHolder;
mLocalState = localState;
mDragResult = result;
}
static DragEvent obtain() {
- return DragEvent.obtain(0, 0f, 0f, null, null, null, false);
+ return DragEvent.obtain(0, 0f, 0f, null, null, null, null, false);
}
/** @hide */
public static DragEvent obtain(int action, float x, float y, Object localState,
- ClipDescription description, ClipData data, boolean result) {
+ ClipDescription description, ClipData data, DropPermissionHolder dropPermissionHolder,
+ boolean result) {
final DragEvent ev;
synchronized (gRecyclerLock) {
if (gRecyclerTop == null) {
ev = new DragEvent();
- ev.init(action, x, y, description, data, localState, result);
+ ev.init(action, x, y, description, data, dropPermissionHolder, localState, result);
return ev;
}
ev = gRecyclerTop;
@@ -285,7 +289,7 @@ public class DragEvent implements Parcelable {
ev.mRecycled = false;
ev.mNext = null;
- ev.init(action, x, y, description, data, localState, result);
+ ev.init(action, x, y, description, data, dropPermissionHolder, localState, result);
return ev;
}
@@ -293,7 +297,8 @@ public class DragEvent implements Parcelable {
/** @hide */
public static DragEvent obtain(DragEvent source) {
return obtain(source.mAction, source.mX, source.mY, source.mLocalState,
- source.mClipDescription, source.mClipData, source.mDragResult);
+ source.mClipDescription, source.mClipData, source.mDropPermissionHolder,
+ source.mDragResult);
}
/**
@@ -358,6 +363,17 @@ public class DragEvent implements Parcelable {
}
/**
+ * Returns the {@link android.view.DropPermissionHolder} object that can be used by the drag
+ * listener to request and release the permissions for the content URIs contained in the
+ * {@link android.content.ClipData} object associated with this event.
+ * This method only returns valid data if the event action is {@link #ACTION_DROP}.
+ * @return The DropPermissionHolder object used to handle content URI permissions.
+ */
+ public DropPermissionHolder getDropPermissionHolder() {
+ return mDropPermissionHolder;
+ }
+
+ /**
* Returns the local state object sent to the system as part of the call to
* {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()}.
* The object is intended to provide local information about the drag and drop operation. For
@@ -477,6 +493,12 @@ public class DragEvent implements Parcelable {
dest.writeInt(1);
mClipDescription.writeToParcel(dest, flags);
}
+ if (mDropPermissionHolder == null) {
+ dest.writeInt(0);
+ } else {
+ dest.writeInt(1);
+ mDropPermissionHolder.writeToParcel(dest, flags);
+ }
}
/**
@@ -496,6 +518,9 @@ public class DragEvent implements Parcelable {
if (in.readInt() != 0) {
event.mClipDescription = ClipDescription.CREATOR.createFromParcel(in);
}
+ if (in.readInt() != 0) {
+ event.mDropPermissionHolder = DropPermissionHolder.CREATOR.createFromParcel(in);
+ }
return event;
}
diff --git a/core/java/android/view/DropPermissionHolder.java b/core/java/android/view/DropPermissionHolder.java
new file mode 100644
index 000000000000..993e67a2578e
--- /dev/null
+++ b/core/java/android/view/DropPermissionHolder.java
@@ -0,0 +1,161 @@
+package android.view;
+
+import android.app.IActivityManager;
+import android.content.ClipData;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import com.android.internal.view.IDropPermissionHolder;
+
+import java.util.ArrayList;
+
+public class DropPermissionHolder implements Parcelable {
+
+ IDropPermissionHolder mDropPermissionHolder;
+
+ /**
+ * Create a new DropPermissionHolder to be passed to the client with a DragEvent.
+ *
+ * @hide
+ */
+ public DropPermissionHolder(ClipData clipData, IActivityManager activityManager,
+ int sourceUid, String targetPackage, int mode, int sourceUserId, int targetUserId) {
+ mDropPermissionHolder = new LocalDropPermissionHolder(clipData, activityManager,
+ sourceUid, targetPackage, mode, sourceUserId, targetUserId);
+ }
+
+ private class LocalDropPermissionHolder extends IDropPermissionHolder.Stub {
+
+ private final IActivityManager mActivityManager;
+ private final int mSourceUid;
+ private final String mTargetPackage;
+ private final int mMode;
+ private final int mSourceUserId;
+ private final int mTargetUserId;
+
+ IBinder mPermissionOwner = null;
+
+ final private ArrayList<Uri> mUris = new ArrayList<Uri>();
+
+ LocalDropPermissionHolder(ClipData clipData, IActivityManager activityManager,
+ int sourceUid, String targetPackage, int mode, int sourceUserId, int targetUserId) {
+ mActivityManager = activityManager;
+ mSourceUid = sourceUid;
+ mTargetPackage = targetPackage;
+ mMode = mode;
+ mSourceUserId = sourceUserId;
+ mTargetUserId = targetUserId;
+
+ int N = clipData.getItemCount();
+ for (int i = 0; i != N; ++i) {
+ ClipData.Item item = clipData.getItemAt(i);
+
+ if (item.getUri() != null) {
+ mUris.add(item.getUri());
+ }
+
+ Intent intent = item.getIntent();
+ if (intent != null && intent.getData() != null) {
+ mUris.add(intent.getData());
+ }
+ }
+ }
+
+ @Override
+ public void grant() throws RemoteException {
+ if (mPermissionOwner != null) {
+ return;
+ }
+
+ mPermissionOwner = mActivityManager.newUriPermissionOwner("drop");
+
+ long origId = Binder.clearCallingIdentity();
+ try {
+ for (Uri mUri : mUris) {
+ mActivityManager.grantUriPermissionFromOwner(
+ mPermissionOwner, mSourceUid, mTargetPackage, mUri, mMode,
+ mSourceUserId, mTargetUserId);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+
+ }
+
+ @Override
+ public void revoke() throws RemoteException {
+ if (mPermissionOwner == null) {
+ return;
+ }
+
+ for (Uri mUri : mUris) {
+ mActivityManager.revokeUriPermissionFromOwner(
+ mPermissionOwner, mUri, mMode, mSourceUserId);
+ }
+
+ mPermissionOwner = null;
+ }
+ }
+
+ /**
+ * Request permissions granted by the activity which started the drag.
+ */
+ public void grant() {
+ try {
+ mDropPermissionHolder.grant();
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Revoke permissions granted by the {@link #grant()} call.
+ */
+ public void revoke() {
+ try {
+ mDropPermissionHolder.revoke();
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Returns information about the {@link android.os.Parcel} representation of this
+ * DropPermissionHolder object.
+ * @return Information about the {@link android.os.Parcel} representation.
+ */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Creates a {@link android.os.Parcel} object from this DropPermissionHolder object.
+ * @param dest A {@link android.os.Parcel} object in which to put the DropPermissionHolder
+ * object.
+ * @param flags Flags to store in the Parcel.
+ */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeStrongBinder(mDropPermissionHolder.asBinder());
+ }
+
+ DropPermissionHolder(Parcel in) {
+ mDropPermissionHolder = IDropPermissionHolder.Stub.asInterface(in.readStrongBinder());
+ }
+
+ /**
+ * A container for creating a DropPermissionHolder from a Parcel.
+ */
+ public static final Parcelable.Creator<DropPermissionHolder> CREATOR
+ = new Parcelable.Creator<DropPermissionHolder>() {
+ public DropPermissionHolder createFromParcel(Parcel in) {
+ return new DropPermissionHolder(in);
+ }
+ public DropPermissionHolder[] newArray(int size) {
+ return new DropPermissionHolder[size];
+ }
+ };
+}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 344b4885d547..7adfa8dbae4f 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -98,11 +98,12 @@ interface IWindowManager
* @param taskBounds Bounds to use when creating a new Task with the input task Id if
* the task doesn't exist yet.
* @param configuration Configuration that is being used with this task.
+ * @param cropWindowsToStack True if the app windows should be cropped to the stack bounds.
*/
void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int userId,
int configChanges, boolean voiceInteraction, boolean launchTaskBehind,
- in Rect taskBounds, in Configuration configuration);
+ in Rect taskBounds, in Configuration configuration, boolean cropWindowsToStack);
/**
*
* @param token The token we are adding to the input task Id.
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 420f7a174d53..dcef14267b7f 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -108,6 +108,11 @@ public class ThreadedRenderer extends HardwareRenderer {
private Choreographer mChoreographer;
private boolean mRootNodeNeedsUpdate;
+ // In case of multi threaded render nodes, these bounds indicate the content bounds against
+ // which the backdrop needs to be cropped against.
+ private final Rect mCurrentContentBounds = new Rect();
+ private final Rect mStagedContentBounds = new Rect();
+
ThreadedRenderer(Context context, boolean translucent) {
final TypedArray a = context.obtainStyledAttributes(null, R.styleable.Lighting, 0, 0);
mLightY = a.getDimension(R.styleable.Lighting_lightY, 0);
@@ -307,6 +312,47 @@ public class ThreadedRenderer extends HardwareRenderer {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
+ /**
+ * Adds a rendernode to the renderer which can be drawn and changed asynchronously to the
+ * rendernode of the UI thread.
+ * @param node The node to add.
+ * @param placeFront If true, the render node will be placed in front of the content node,
+ * otherwise behind the content node.
+ */
+ public void addRenderNode(RenderNode node, boolean placeFront) {
+ nAddRenderNode(mNativeProxy, node.mNativeRenderNode, placeFront);
+ }
+
+ /**
+ * Only especially added render nodes can be removed.
+ * @param node The node which was added via addRenderNode which should get removed again.
+ */
+ public void removeRenderNode(RenderNode node) {
+ nRemoveRenderNode(mNativeProxy, node.mNativeRenderNode);
+ }
+
+ /**
+ * Draws a particular render node. If the node is not the content node, only the additional
+ * nodes will get drawn and the content remains untouched.
+ * @param node The node to be drawn.
+ */
+ public void drawRenderNode(RenderNode node) {
+ nDrawRenderNode(mNativeProxy, node.mNativeRenderNode);
+ }
+
+ /**
+ * To avoid unnecessary overdrawing of the main content all additionally passed render nodes
+ * will be prevented to overdraw this area. It will be synchronized with the draw call.
+ * This should be updated in the content view's draw call.
+ * @param left The left side of the protected bounds.
+ * @param top The top side of the protected bounds.
+ * @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) {
+ mStagedContentBounds.set(left, top, right, bottom);
+ }
+
@Override
void invalidateRoot() {
mRootNodeNeedsUpdate = true;
@@ -320,6 +366,14 @@ public class ThreadedRenderer extends HardwareRenderer {
choreographer.mFrameInfo.markDrawStart();
updateRootDisplayList(view, callbacks);
+ // The main content view was updating the content bounds and we transfer them to the
+ // renderer.
+ if (!mCurrentContentBounds.equals(mStagedContentBounds)) {
+ mCurrentContentBounds.set(mStagedContentBounds);
+ nSetContentOverdrawProtectionBounds(mNativeProxy, mCurrentContentBounds.left,
+ mCurrentContentBounds.top, mCurrentContentBounds.right,
+ mCurrentContentBounds.bottom);
+ }
attachInfo.mIgnoreDirtyState = false;
@@ -541,4 +595,11 @@ public class ThreadedRenderer extends HardwareRenderer {
private static native void nDumpProfileInfo(long nativeProxy, FileDescriptor fd,
@DumpFlags int dumpFlags);
private static native void nDumpProfileData(byte[] data, FileDescriptor fd);
+
+ private static native void nAddRenderNode(long nativeProxy, long rootRenderNode,
+ 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,
+ int top, int right, int bottom);
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index eb591c1bfa86..263ec7d18f08 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3641,9 +3641,44 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* with this flag set, all visible applications will be able to participate
* in the drag operation and receive the dragged content.
*
- * @hide
+ * If this is the only flag set, then the drag recipient will only have access to text data
+ * and intents contained in the {@link ClipData} object. Access to URIs contained in the
+ * {@link ClipData} is determined by other DRAG_FLAG_GLOBAL_* flags.
+ */
+ public static final int DRAG_FLAG_GLOBAL = 1 << 8; // 256
+
+ /**
+ * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to
+ * request read access to the content URI(s) contained in the {@link ClipData} object.
+ * @see android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION
+ */
+ public static final int DRAG_FLAG_GLOBAL_URI_READ = Intent.FLAG_GRANT_READ_URI_PERMISSION;
+
+ /**
+ * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to
+ * request write access to the content URI(s) contained in the {@link ClipData} object.
+ * @see android.content.Intent.FLAG_GRANT_WRITE_URI_PERMISSION
+ */
+ public static final int DRAG_FLAG_GLOBAL_URI_WRITE = Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
+
+ /**
+ * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link
+ * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant can be persisted across device
+ * reboots until explicitly revoked with
+ * {@link android.content.Context#revokeUriPermission(Uri,int) Context.revokeUriPermission}.
+ * @see android.content.Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
+ */
+ public static final int DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION =
+ Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION;
+
+ /**
+ * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link
+ * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant applies to any URI that is a prefix
+ * match against the original granted URI.
+ * @see android.content.Intent.FLAG_GRANT_PREFIX_URI_PERMISSION
*/
- public static final int DRAG_FLAG_GLOBAL = 1;
+ public static final int DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION =
+ Intent.FLAG_GRANT_PREFIX_URI_PERMISSION;
/**
* Flag indicating that the drag shadow will be opaque. When
@@ -4671,7 +4706,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
out.append(" #");
out.append(Integer.toHexString(id));
final Resources r = mResources;
- if (Resources.resourceHasPackage(id) && r != null) {
+ if (id > 0 && Resources.resourceHasPackage(id) && r != null) {
try {
String pkgname;
switch (id&0xff000000) {
@@ -5353,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;
}
@@ -5374,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);
}
/**
@@ -7338,6 +7370,23 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
+ * Compute the view's coordinate within the surface.
+ *
+ * <p>Computes the coordinates of this view in its surface. The argument
+ * must be an array of two integers. After the method returns, the array
+ * contains the x and y location in that order.</p>
+ * @hide
+ * @param location an array of two integers in which to hold the coordinates
+ */
+ public void getLocationInSurface(@Size(2) int[] location) {
+ getLocationInWindow(location);
+ if (mAttachInfo != null && mAttachInfo.mViewRootImpl != null) {
+ location[0] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.left;
+ location[1] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.top;
+ }
+ }
+
+ /**
* Provide original WindowInsets that are dispatched to the view hierarchy. The insets are
* only available if the view is attached.
*
@@ -8408,11 +8457,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
public void clearAccessibilityFocus() {
clearAccessibilityFocusNoCallbacks();
- // Clear the global reference of accessibility focus if this
- // view or any of its descendants had accessibility focus.
- ViewRootImpl viewRootImpl = getViewRootImpl();
+
+ // Clear the global reference of accessibility focus if this view or
+ // any of its descendants had accessibility focus. This will NOT send
+ // an event or update internal state if focus is cleared from a
+ // descendant view, which may leave views in inconsistent states.
+ final ViewRootImpl viewRootImpl = getViewRootImpl();
if (viewRootImpl != null) {
- View focusHost = viewRootImpl.getAccessibilityFocusedHost();
+ final View focusHost = viewRootImpl.getAccessibilityFocusedHost();
if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) {
viewRootImpl.setAccessibilityFocus(null, null);
}
@@ -8688,6 +8740,18 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
public void setImportantForAccessibility(int mode) {
final int oldMode = getImportantForAccessibility();
if (mode != oldMode) {
+ final boolean hideDescendants =
+ mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS;
+
+ // If this node or its descendants are no longer important, try to
+ // clear accessibility focus.
+ if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO || hideDescendants) {
+ final View focusHost = findAccessibilityFocusHost(hideDescendants);
+ if (focusHost != null) {
+ focusHost.clearAccessibilityFocus();
+ }
+ }
+
// If we're moving between AUTO and another state, we might not need
// to send a subtree changed notification. We'll store the computed
// importance, since we'll need to check it later to make sure.
@@ -8707,6 +8771,31 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
+ * Returns the view within this view's hierarchy that is hosting
+ * accessibility focus.
+ *
+ * @param searchDescendants whether to search for focus in descendant views
+ * @return the view hosting accessibility focus, or {@code null}
+ */
+ private View findAccessibilityFocusHost(boolean searchDescendants) {
+ if (isAccessibilityFocusedViewOrHost()) {
+ return this;
+ }
+
+ if (searchDescendants) {
+ final ViewRootImpl viewRoot = getViewRootImpl();
+ if (viewRoot != null) {
+ final View focusHost = viewRoot.getAccessibilityFocusedHost();
+ if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) {
+ return focusHost;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
* Computes whether this view should be exposed for accessibility. In
* general, views that are interactive or provide information are exposed
* while views that serve only as containers are hidden.
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 d26e91408666..f6c60ed688a5 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -169,6 +169,16 @@ public final class ViewRootImpl implements ViewParent,
boolean mAppVisible = true;
int mOrigWindowType = -1;
+ /** Whether the window had focus during the most recent traversal. */
+ boolean mHadWindowFocus;
+
+ /**
+ * Whether the window lost focus during a previous traversal and has not
+ * yet gained it back. Used to determine whether a WINDOW_STATE_CHANGE
+ * accessibility events should be sent during traversal.
+ */
+ boolean mLostWindowFocus;
+
// Set to true if the owner of this window is in the stopped state,
// so the window should no longer be active.
boolean mStopped = false;
@@ -191,6 +201,10 @@ public final class ViewRootImpl implements ViewParent,
Rect mDirty;
boolean mIsAnimating;
+ private boolean mDragResizing;
+ private int mCanvasOffsetX;
+ private int mCanvasOffsetY;
+
CompatibilityInfo.Translator mTranslator;
final View.AttachInfo mAttachInfo;
@@ -576,21 +590,20 @@ public final class ViewRootImpl implements ViewParent,
// right away, anyway.
return;
case WindowManagerGlobal.ADD_MULTIPLE_SINGLETON:
- throw new WindowManager.BadTokenException(
- "Unable to add window " + mWindow +
- " -- another window of this type already exists");
+ throw new WindowManager.BadTokenException("Unable to add window "
+ + mWindow + " -- another window of type "
+ + mWindowAttributes.type + " already exists");
case WindowManagerGlobal.ADD_PERMISSION_DENIED:
- throw new WindowManager.BadTokenException(
- "Unable to add window " + mWindow +
- " -- permission denied for this window type");
+ throw new WindowManager.BadTokenException("Unable to add window "
+ + mWindow + " -- permission denied for window type "
+ + mWindowAttributes.type);
case WindowManagerGlobal.ADD_INVALID_DISPLAY:
- throw new WindowManager.InvalidDisplayException(
- "Unable to add window " + mWindow +
- " -- the specified display can not be found");
+ throw new WindowManager.InvalidDisplayException("Unable to add window "
+ + mWindow + " -- the specified display can not be found");
case WindowManagerGlobal.ADD_INVALID_TYPE:
- throw new WindowManager.InvalidDisplayException(
- "Unable to add window " + mWindow
- + " -- the specified window type is not valid");
+ throw new WindowManager.InvalidDisplayException("Unable to add window "
+ + mWindow + " -- the specified window type "
+ + mWindowAttributes.type + " is not valid");
}
throw new RuntimeException(
"Unable to add window -- unknown error code " + res);
@@ -1507,6 +1520,7 @@ public final class ViewRootImpl implements ViewParent,
frame.width() < desiredWindowWidth && frame.width() != mWidth)
|| (lp.height == ViewGroup.LayoutParams.WRAP_CONTENT &&
frame.height() < desiredWindowHeight && frame.height() != mHeight));
+ windowShouldResize |= mDragResizing;
// Determine whether to compute insets.
// If there are no inset listeners remaining then we may still need to compute
@@ -1518,10 +1532,11 @@ public final class ViewRootImpl implements ViewParent,
boolean insetsPending = false;
int relayoutResult = 0;
+ boolean isViewVisible = viewVisibility == View.VISIBLE;
if (mFirst || windowShouldResize || insetsChanged ||
viewVisibilityChanged || params != null) {
- if (viewVisibility == View.VISIBLE) {
+ if (isViewVisible) {
// If this window is giving internal insets to the window
// manager, and it is being added or changing its visibility,
// then we want to first give the window manager "fake"
@@ -1682,6 +1697,19 @@ public final class ViewRootImpl implements ViewParent,
return;
}
}
+
+ final boolean dragResizing = (relayoutResult
+ & WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING) != 0;
+ if (mDragResizing != dragResizing) {
+ mDragResizing = dragResizing;
+ mFullRedrawNeeded = true;
+ }
+ if (dragResizing) {
+ mCanvasOffsetX = mWinFrame.left;
+ mCanvasOffsetY = mWinFrame.top;
+ } else {
+ mCanvasOffsetX = mCanvasOffsetY = 0;
+ }
} catch (RemoteException e) {
}
@@ -1759,10 +1787,6 @@ public final class ViewRootImpl implements ViewParent,
|| mHeight != hardwareRenderer.getHeight()) {
hardwareRenderer.setup(mWidth, mHeight, mAttachInfo,
mWindowAttributes.surfaceInsets);
- if (!hwInitialized) {
- hardwareRenderer.invalidate(mSurface);
- mFullRedrawNeeded = true;
- }
}
}
@@ -1947,19 +1971,33 @@ public final class ViewRootImpl implements ViewParent,
mRemainingFrameCount--;
}
+ final boolean changedVisibility = (viewVisibilityChanged || mFirst) && isViewVisible;
+ final boolean hasWindowFocus = mAttachInfo.mHasWindowFocus && isViewVisible;
+ final boolean regainedFocus = hasWindowFocus && mLostWindowFocus;
+ if (regainedFocus) {
+ mLostWindowFocus = false;
+ } else if (!hasWindowFocus && mHadWindowFocus) {
+ mLostWindowFocus = true;
+ }
+
+ if (changedVisibility || regainedFocus) {
+ host.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+ }
+
mFirst = false;
mWillDrawSoon = false;
mNewSurfaceNeeded = false;
mViewVisibility = viewVisibility;
+ mHadWindowFocus = hasWindowFocus;
- if (mAttachInfo.mHasWindowFocus && !isInLocalFocusMode()) {
+ if (hasWindowFocus && !isInLocalFocusMode()) {
final boolean imTarget = WindowManager.LayoutParams
.mayUseInputMethod(mWindowAttributes.flags);
if (imTarget != mLastWasImTarget) {
mLastWasImTarget = imTarget;
InputMethodManager imm = InputMethodManager.peekInstance();
if (imm != null && imTarget) {
- imm.onPreWindowFocus(mView, true /* hasWindowFocus */);
+ imm.onPreWindowFocus(mView, hasWindowFocus);
imm.onPostWindowFocus(mView, mView.findFocus(),
mWindowAttributes.softInputMode,
!mHasHadWindowFocus, mWindowAttributes.flags);
@@ -1972,8 +2010,7 @@ public final class ViewRootImpl implements ViewParent,
mReportNextDraw = true;
}
- boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() ||
- viewVisibility != View.VISIBLE;
+ boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible;
if (!cancelDraw && !newSurface) {
if (!skipDraw || mReportNextDraw) {
@@ -1987,7 +2024,7 @@ public final class ViewRootImpl implements ViewParent,
performDraw();
}
} else {
- if (viewVisibility == View.VISIBLE) {
+ if (isViewVisible) {
// Try again
scheduleTraversals();
} else if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
@@ -2464,8 +2501,8 @@ public final class ViewRootImpl implements ViewParent,
mAttachInfo.mTreeObserver.dispatchOnDraw();
- int xOffset = 0;
- int yOffset = curScrollY;
+ int xOffset = -mCanvasOffsetX;
+ int yOffset = -mCanvasOffsetY + curScrollY;
final WindowManager.LayoutParams params = mWindowAttributes;
final Rect surfaceInsets = params != null ? params.surfaceInsets : null;
if (surfaceInsets != null) {
@@ -3296,13 +3333,6 @@ public final class ViewRootImpl implements ViewParent,
~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
mHasHadWindowFocus = true;
}
-
- if (mView != null && mAccessibilityManager.isEnabled()) {
- if (hasWindowFocus) {
- mView.sendAccessibilityEvent(
- AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
- }
- }
}
} break;
case MSG_DIE:
@@ -6210,6 +6240,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;
}
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index b146a51292e1..0e7089ff7a8c 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -1175,6 +1175,13 @@ public abstract class Window {
public abstract void addContentView(View view, ViewGroup.LayoutParams params);
/**
+ * Remove the view that was used as the screen content.
+ *
+ * @hide
+ */
+ public abstract void clearContentView();
+
+ /**
* Return the view in this Window that currently has focus, or null if
* there are none. Note that this does not look in any containing
* Window.
@@ -1239,6 +1246,15 @@ public abstract class Window {
public void setElevation(float elevation) {}
/**
+ * Gets the window elevation.
+ *
+ * @hide
+ */
+ public float getElevation() {
+ return 0.0f;
+ }
+
+ /**
* Sets whether window content should be clipped to the outline of the
* window background.
*
@@ -1991,5 +2007,13 @@ public abstract class Window {
*/
public abstract void setNavigationBarColor(@ColorInt int color);
-
+ /**
+ * Get information whether the activity has non client decoration view. These views are used in
+ * the multi window environment, to provide dragging handle and maximize/close buttons.
+ *
+ * @hide
+ */
+ public boolean hasNonClientDecorView() {
+ return false;
+ }
}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 45bc1df33469..92e473db556f 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -226,6 +226,7 @@ public interface WindowManager extends ViewManager {
@ViewDebug.IntToString(from = TYPE_PRIVATE_PRESENTATION, to = "TYPE_PRIVATE_PRESENTATION"),
@ViewDebug.IntToString(from = TYPE_VOICE_INTERACTION, to = "TYPE_VOICE_INTERACTION"),
@ViewDebug.IntToString(from = TYPE_VOICE_INTERACTION_STARTING, to = "TYPE_VOICE_INTERACTION_STARTING"),
+ @ViewDebug.IntToString(from = TYPE_DOCK_DIVIDER, to = "TYPE_DOCK_DIVIDER"),
})
public int type;
@@ -565,6 +566,13 @@ public interface WindowManager extends ViewManager {
public static final int TYPE_VOICE_INTERACTION_STARTING = FIRST_SYSTEM_WINDOW+33;
/**
+ * Window for displaying a handle used for resizing docked stacks. This window is owned
+ * by the system process.
+ * @hide
+ */
+ public static final int TYPE_DOCK_DIVIDER = FIRST_SYSTEM_WINDOW+34;
+
+ /**
* End of types of system windows.
*/
public static final int LAST_SYSTEM_WINDOW = 2999;
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index 606168ccce9a..ab99b9efae69 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -70,6 +70,13 @@ public final class WindowManagerGlobal {
public static final int RELAYOUT_RES_SURFACE_CHANGED = 0x4;
/**
+ * The window is being resized by dragging one of the window corners,
+ * in this case the surface would be fullsreen-sized. The client should
+ * render to the actual frame location (instead of (0,curScrollY)).
+ */
+ public static final int RELAYOUT_RES_DRAG_RESIZING = 0x8;
+
+ /**
* Flag for relayout: the client will be later giving
* internal insets; as a result, the window will not impact other window
* layouts until the insets are given.
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 057b7010999a..d0c50c9309c2 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -962,6 +962,9 @@ public class WebView extends AbsoluteLayout
* If the base URL uses any other scheme, then the data will be loaded into
* the WebView as a plain string (i.e. not part of a data URL) and any URL-encoded
* entities in the string will not be decoded.
+ * <p>
+ * Note that the baseUrl is sent in the 'Referer' HTTP header when
+ * requesting subresources (images, etc.) of the page loaded using this method.
*
* @param baseUrl the URL to use as the page's base URL. If null defaults to
* 'about:blank'.
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 389fc0a506a2..b8faf0c6cf98 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -2398,6 +2398,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
lp.itemId = mAdapter.getItemId(position);
}
lp.viewType = mAdapter.getItemViewType(position);
+ lp.isEnabled = mAdapter.isEnabled(position);
if (lp != vlp) {
child.setLayoutParams(lp);
}
@@ -2419,19 +2420,33 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
final int position = getPositionForView(host);
- final ListAdapter adapter = getAdapter();
-
- if ((position == INVALID_POSITION) || (adapter == null)) {
+ if (position == INVALID_POSITION || mAdapter == null) {
// Cannot perform actions on invalid items.
return false;
}
- if (!isEnabled() || !adapter.isEnabled(position)) {
- // Cannot perform actions on disabled items.
+ if (position >= mAdapter.getCount()) {
+ // The position is no longer valid, likely due to a data set
+ // change. We could fail here for all data set changes, since
+ // there is a chance that the data bound to the view may no
+ // longer exist at the same position within the adapter, but
+ // it's more consistent with the standard touch interaction to
+ // click at whatever may have moved into that position.
return false;
}
- final long id = getItemIdAtPosition(position);
+ final boolean isItemEnabled;
+ final ViewGroup.LayoutParams lp = host.getLayoutParams();
+ if (lp instanceof AbsListView.LayoutParams) {
+ isItemEnabled = ((AbsListView.LayoutParams) lp).isEnabled;
+ } else {
+ isItemEnabled = false;
+ }
+
+ if (!isEnabled() || !isItemEnabled) {
+ // Cannot perform actions on disabled items.
+ return false;
+ }
switch (action) {
case AccessibilityNodeInfo.ACTION_CLEAR_SELECTION: {
@@ -2447,12 +2462,14 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
} return false;
case AccessibilityNodeInfo.ACTION_CLICK: {
- if (isItemClickable(host, position)) {
+ if (isItemClickable(host)) {
+ final long id = getItemIdAtPosition(position);
return performItemClick(host, position, id);
}
} return false;
case AccessibilityNodeInfo.ACTION_LONG_CLICK: {
if (isLongClickable()) {
+ final long id = getItemIdAtPosition(position);
return performLongPress(host, position, id);
}
} return false;
@@ -2472,13 +2489,20 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
*/
public void onInitializeAccessibilityNodeInfoForItem(
View view, int position, AccessibilityNodeInfo info) {
- final ListAdapter adapter = getAdapter();
- if (position == INVALID_POSITION || adapter == null) {
+ if (position == INVALID_POSITION) {
// The item doesn't exist, so there's not much we can do here.
return;
}
- if (!isEnabled() || !adapter.isEnabled(position)) {
+ final boolean isItemEnabled;
+ final ViewGroup.LayoutParams lp = view.getLayoutParams();
+ if (lp instanceof AbsListView.LayoutParams) {
+ isItemEnabled = ((AbsListView.LayoutParams) lp).isEnabled;
+ } else {
+ isItemEnabled = false;
+ }
+
+ if (!isEnabled() || !isItemEnabled) {
info.setEnabled(false);
return;
}
@@ -2490,7 +2514,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
info.addAction(AccessibilityAction.ACTION_SELECT);
}
- if (isItemClickable(view, position)) {
+ if (isItemClickable(view)) {
info.addAction(AccessibilityAction.ACTION_CLICK);
info.setClickable(true);
}
@@ -2501,9 +2525,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
}
- private boolean isItemClickable(View view, int position) {
- return mAdapter != null && view != null &&
- mAdapter.isEnabled(position) && !view.hasFocusable();
+ private boolean isItemClickable(View view) {
+ return !view.hasFocusable();
}
/**
@@ -3057,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;
@@ -3067,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;
@@ -3123,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 &&
@@ -3140,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);
@@ -3155,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
@@ -3318,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 {
@@ -6326,6 +6377,9 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
*/
long itemId = -1;
+ /** Whether the adapter considers the item enabled. */
+ boolean isEnabled;
+
public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
}
@@ -6351,6 +6405,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
encoder.addProperty("list:viewType", viewType);
encoder.addProperty("list:recycledHeaderFooter", recycledHeaderFooter);
encoder.addProperty("list:forceAdd", forceAdd);
+ encoder.addProperty("list:isEnabled", isEnabled);
}
}
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index 6883db266e99..68855ff72531 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -385,17 +385,19 @@ public abstract class AbsSeekBar extends ProgressBar {
}
@Override
- void onProgressRefresh(float scale, boolean fromUser, int progress) {
- super.onProgressRefresh(scale, fromUser, progress);
+ void onVisualProgressChanged(int id, float scale) {
+ super.onVisualProgressChanged(id, scale);
- final Drawable thumb = mThumb;
- if (thumb != null) {
- setThumbPos(getWidth(), thumb, scale, Integer.MIN_VALUE);
+ if (id == R.id.progress) {
+ final Drawable thumb = mThumb;
+ if (thumb != null) {
+ setThumbPos(getWidth(), thumb, scale, Integer.MIN_VALUE);
- // Since we draw translated, the drawable's bounds that it signals
- // for invalidation won't be the actual bounds we want invalidated,
- // so just invalidate this whole view.
- invalidate();
+ // Since we draw translated, the drawable's bounds that it signals
+ // for invalidation won't be the actual bounds we want invalidated,
+ // so just invalidate this whole view.
+ invalidate();
+ }
}
}
@@ -709,8 +711,7 @@ public abstract class AbsSeekBar extends ProgressBar {
case KeyEvent.KEYCODE_DPAD_RIGHT:
increment = isLayoutRtl() ? -increment : increment;
- // Let progress bar handle clamping values.
- if (setProgress(getProgress() + increment, true)) {
+ if (setProgressInternal(getProgress() + increment, true, true)) {
onKeyChange();
return true;
}
@@ -764,7 +765,7 @@ public abstract class AbsSeekBar extends ProgressBar {
}
float value = arguments.getFloat(
AccessibilityNodeInfo.ACTION_ARGUMENT_PROGRESS_VALUE);
- return setProgress((int) value, true);
+ return setProgressInternal((int) value, true, true);
}
case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD:
case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: {
@@ -777,7 +778,7 @@ public abstract class AbsSeekBar extends ProgressBar {
}
// Let progress bar handle clamping values.
- if (setProgress(getProgress() + increment, true)) {
+ if (setProgressInternal(getProgress() + increment, true, true)) {
onKeyChange();
return true;
}
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index 0cc1b25d19b7..6ed7ab8fde68 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -600,13 +600,20 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup {
}
/**
- * Get the position within the adapter's data set for the view, where view is a an adapter item
- * or a descendant of an adapter item.
+ * Returns the position within the adapter's data set for the view, where
+ * view is a an adapter item or a descendant of an adapter item.
+ * <p>
+ * <strong>Note:</strong> The result of this method only reflects the
+ * position of the data bound to <var>view</var> during the most recent
+ * layout pass. If the adapter's data set has changed without a subsequent
+ * layout pass, the position returned by this method may not match the
+ * current position of the data within the adapter.
*
- * @param view an adapter item, or a descendant of an adapter item. This must be visible in this
- * AdapterView at the time of the call.
- * @return the position within the adapter's data set of the view, or {@link #INVALID_POSITION}
- * if the view does not correspond to a list item (or it is not currently visible).
+ * @param view an adapter item, or a descendant of an adapter item. This
+ * must be visible in this AdapterView at the time of the call.
+ * @return the position within the adapter's data set of the view, or
+ * {@link #INVALID_POSITION} if the view does not correspond to a
+ * list item (or it is not currently visible)
*/
public int getPositionForView(View view) {
View listItem = view;
@@ -808,6 +815,7 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup {
@Override
protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
dispatchThawSelfOnly(container);
+ handleDataChanged();
}
class AdapterDataSetObserver extends DataSetObserver {
diff --git a/core/java/android/widget/DropDownListView.java b/core/java/android/widget/DropDownListView.java
index bcbafc9af158..c869ccbdef58 100644
--- a/core/java/android/widget/DropDownListView.java
+++ b/core/java/android/widget/DropDownListView.java
@@ -132,11 +132,6 @@ public class DropDownListView extends ListView {
return selectedView != null && selectedView.isEnabled() || super.shouldShowSelector();
}
- protected void clearSelection() {
- setSelectedPositionInt(-1);
- setNextSelectedPositionInt(-1);
- }
-
@Override
public boolean onHoverEvent(MotionEvent ev) {
final int action = ev.getActionMasked();
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index f994d4ad91be..607e955d5698 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -1070,6 +1070,7 @@ public class GridView extends AbsListView {
child.setLayoutParams(p);
}
p.viewType = mAdapter.getItemViewType(0);
+ p.isEnabled = mAdapter.isEnabled(0);
p.forceAdd = true;
int childHeightSpec = getChildMeasureSpec(
@@ -1480,6 +1481,7 @@ public class GridView extends AbsListView {
p = (AbsListView.LayoutParams) generateDefaultLayoutParams();
}
p.viewType = mAdapter.getItemViewType(position);
+ p.isEnabled = mAdapter.isEnabled(position);
if (recycled && !p.forceAdd) {
attachViewToParent(child, where, p);
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index be839742af45..53ca6d1ba3b1 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -1200,6 +1200,7 @@ public class ListView extends AbsListView {
child.setLayoutParams(p);
}
p.viewType = mAdapter.getItemViewType(position);
+ p.isEnabled = mAdapter.isEnabled(position);
p.forceAdd = true;
final int childWidthSpec = ViewGroup.getChildMeasureSpec(widthMeasureSpec,
@@ -1913,6 +1914,7 @@ public class ListView extends AbsListView {
p = (AbsListView.LayoutParams) generateDefaultLayoutParams();
}
p.viewType = mAdapter.getItemViewType(position);
+ p.isEnabled = mAdapter.isEnabled(position);
if ((recycled && !p.forceAdd) || (p.recycledHeaderFooter
&& p.viewType == AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER)) {
diff --git a/core/java/android/widget/MenuItemHoverListener.java b/core/java/android/widget/MenuItemHoverListener.java
new file mode 100644
index 000000000000..87c5c852973e
--- /dev/null
+++ b/core/java/android/widget/MenuItemHoverListener.java
@@ -0,0 +1,13 @@
+package android.widget;
+
+import com.android.internal.view.menu.MenuBuilder;
+
+/**
+ * An interface notified when a menu item is hovered. Useful for cases when hover should trigger
+ * some behavior at a higher level, like managing the opening and closing of submenus.
+ *
+ * @hide
+ */
+public interface MenuItemHoverListener {
+ public void onItemHovered(MenuBuilder menu, int position);
+}
diff --git a/core/java/android/widget/MenuPopupWindow.java b/core/java/android/widget/MenuPopupWindow.java
index 900aa326d502..1fb62d0fa6c9 100644
--- a/core/java/android/widget/MenuPopupWindow.java
+++ b/core/java/android/widget/MenuPopupWindow.java
@@ -22,12 +22,12 @@ import android.content.res.Resources;
import android.transition.Transition;
import android.util.AttributeSet;
import android.view.KeyEvent;
+import android.view.MotionEvent;
import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewParent;
import com.android.internal.view.menu.ListMenuItemView;
import com.android.internal.view.menu.MenuAdapter;
+import com.android.internal.view.menu.MenuBuilder;
/**
* A MenuPopupWindow represents the popup window for menu.
@@ -37,20 +37,32 @@ import com.android.internal.view.menu.MenuAdapter;
*
* @hide
*/
-public class MenuPopupWindow extends ListPopupWindow {
+public class MenuPopupWindow extends ListPopupWindow implements MenuItemHoverListener {
+ private MenuItemHoverListener mHoverListener;
+
public MenuPopupWindow(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
DropDownListView createDropDownListView(Context context, boolean hijackFocus) {
- return new MenuDropDownListView(context, hijackFocus);
+ MenuDropDownListView view = new MenuDropDownListView(context, hijackFocus);
+ view.setHoverListener(this);
+ return view;
}
public void setEnterTransition(Transition enterTransition) {
mPopup.setEnterTransition(enterTransition);
}
+ public void setExitTransition(Transition exitTransition) {
+ mPopup.setExitTransition(exitTransition);
+ }
+
+ public void setHoverListener(MenuItemHoverListener hoverListener) {
+ mHoverListener = hoverListener;
+ }
+
/**
* Set whether this window is touch modal or if outside touches will be sent to
* other windows behind it.
@@ -59,10 +71,23 @@ public class MenuPopupWindow extends ListPopupWindow {
mPopup.setTouchModal(touchModal);
}
- private static class MenuDropDownListView extends DropDownListView {
+ @Override
+ public void onItemHovered(MenuBuilder menu, int position) {
+ // Forward up the chain
+ if (mHoverListener != null) {
+ mHoverListener.onItemHovered(menu, position);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public static class MenuDropDownListView extends DropDownListView {
final int mAdvanceKey;
final int mRetreatKey;
+ private MenuItemHoverListener mHoverListener;
+
public MenuDropDownListView(Context context, boolean hijackFocus) {
super(context, hijackFocus);
@@ -77,6 +102,15 @@ public class MenuPopupWindow extends ListPopupWindow {
}
}
+ public void setHoverListener(MenuItemHoverListener hoverListener) {
+ mHoverListener = hoverListener;
+ }
+
+ public void clearSelection() {
+ setSelectedPositionInt(INVALID_POSITION);
+ setNextSelectedPositionInt(INVALID_POSITION);
+ }
+
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
ListMenuItemView selectedItem = (ListMenuItemView) getSelectedView();
@@ -90,8 +124,8 @@ public class MenuPopupWindow extends ListPopupWindow {
}
return true;
} else if (selectedItem != null && keyCode == mRetreatKey) {
- setSelectedPositionInt(-1);
- setNextSelectedPositionInt(-1);
+ setSelectedPositionInt(INVALID_POSITION);
+ setNextSelectedPositionInt(INVALID_POSITION);
((MenuAdapter) getAdapter()).getAdapterMenu().close();
return true;
@@ -99,6 +133,38 @@ public class MenuPopupWindow extends ListPopupWindow {
return super.onKeyDown(keyCode, event);
}
- }
+ @Override
+ public boolean onHoverEvent(MotionEvent ev) {
+ boolean dispatchHover = false;
+ final int position = pointToPosition((int) ev.getX(), (int) ev.getY());
+
+ final int action = ev.getActionMasked();
+ if (action == MotionEvent.ACTION_HOVER_ENTER
+ || action == MotionEvent.ACTION_HOVER_MOVE) {
+ if (position != INVALID_POSITION && position != mSelectedPosition) {
+ final View hoveredItem = getChildAt(position - getFirstVisiblePosition());
+ if (hoveredItem.isEnabled()) {
+ dispatchHover = true;
+ }
+ }
+ }
+ boolean superVal = super.onHoverEvent(ev);
+
+ if (dispatchHover && mHoverListener != null) {
+ 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;
+ }
+ }
} \ No newline at end of file
diff --git a/core/java/android/widget/PopupMenu.java b/core/java/android/widget/PopupMenu.java
index bd1fbb8f29c5..34a843925700 100644
--- a/core/java/android/widget/PopupMenu.java
+++ b/core/java/android/widget/PopupMenu.java
@@ -270,25 +270,8 @@ public class PopupMenu implements MenuBuilder.Callback, MenuPresenter.Callback {
* @hide
*/
public boolean onOpenSubMenu(MenuBuilder subMenu) {
- if (subMenu == null) return false;
-
- if (!subMenu.hasVisibleItems()) {
- return true;
- }
-
- if (!mShowCascadingMenus) {
- // Current menu will be dismissed by the normal helper, submenu will be shown in its
- // place. (If cascading menus are enabled, the cascading implementation will show the
- // submenu itself).
- new MenuPopupHelper(mContext, subMenu, mAnchor).show();
- }
- return true;
- }
-
- /**
- * @hide
- */
- public void onCloseSubMenu(SubMenuBuilder menu) {
+ // The menu presenter will handle opening the submenu itself. Nothing to do here.
+ return false;
}
/**
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index f9fa0272f147..864a0fe72fa1 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -1449,11 +1449,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 +1471,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);
+ }
}
}
@@ -1542,7 +1552,13 @@ public class PopupWindow {
Resources res = anchor.getContext().getResources();
bottomEdge = res.getDisplayMetrics().heightPixels;
}
- final int distanceToBottom = bottomEdge - (anchorPos[1] + anchor.getHeight()) - yOffset;
+
+ final int distanceToBottom;
+ if (mOverlapAnchor) {
+ distanceToBottom = bottomEdge - anchorPos[1] - yOffset;
+ } else {
+ 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/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index fce3754749ef..04c68ae600ea 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -16,10 +16,13 @@
package android.widget;
+import android.animation.ObjectAnimator;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.PorterDuff;
+import android.util.FloatProperty;
+import android.util.IntProperty;
import android.view.accessibility.AccessibilityNodeInfo;
import com.android.internal.R;
@@ -28,7 +31,6 @@ import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
-import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.Shader;
@@ -38,7 +40,6 @@ import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ClipDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
-import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.StateListDrawable;
import android.graphics.drawable.shapes.RoundRectShape;
import android.graphics.drawable.shapes.Shape;
@@ -57,6 +58,7 @@ import android.view.accessibility.AccessibilityManager;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
+import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
import android.view.animation.Transformation;
@@ -198,9 +200,17 @@ import java.util.ArrayList;
*/
@RemoteView
public class ProgressBar extends View {
+
private static final int MAX_LEVEL = 10000;
private static final int TIMEOUT_SEND_ACCESSIBILITY_EVENT = 200;
+ /** Interpolator used for smooth progress animations. */
+ private static final DecelerateInterpolator PROGRESS_ANIM_INTERPOLATOR =
+ new DecelerateInterpolator();
+
+ /** Duration of smooth progress animations. */
+ private static final int PROGRESS_ANIM_DURATION = 80;
+
int mMinWidth;
int mMaxWidth;
int mMinHeight;
@@ -234,6 +244,9 @@ public class ProgressBar extends View {
private boolean mAttached;
private boolean mRefreshIsPosted;
+ /** Value used to track progress animation, in the range [0...1]. */
+ private float mVisualProgress;
+
boolean mMirrorForRtl = false;
private final ArrayList<RefreshData> mRefreshData = new ArrayList<RefreshData>();
@@ -814,8 +827,8 @@ public class ProgressBar extends View {
updateDrawableBounds(getWidth(), getHeight());
updateDrawableState();
- doRefreshProgress(R.id.progress, mProgress, false, false);
- doRefreshProgress(R.id.secondaryProgress, mSecondaryProgress, false, false);
+ doRefreshProgress(R.id.progress, mProgress, false, false, false);
+ doRefreshProgress(R.id.secondaryProgress, mSecondaryProgress, false, false, false);
}
}
@@ -1246,7 +1259,7 @@ public class ProgressBar extends View {
final int count = mRefreshData.size();
for (int i = 0; i < count; i++) {
final RefreshData rd = mRefreshData.get(i);
- doRefreshProgress(rd.id, rd.progress, rd.fromUser, true);
+ doRefreshProgress(rd.id, rd.progress, rd.fromUser, true, rd.animate);
rd.recycle();
}
mRefreshData.clear();
@@ -1263,8 +1276,9 @@ public class ProgressBar extends View {
public int id;
public int progress;
public boolean fromUser;
+ public boolean animate;
- public static RefreshData obtain(int id, int progress, boolean fromUser) {
+ public static RefreshData obtain(int id, int progress, boolean fromUser, boolean animate) {
RefreshData rd = sPool.acquire();
if (rd == null) {
rd = new RefreshData();
@@ -1272,6 +1286,7 @@ public class ProgressBar extends View {
rd.id = id;
rd.progress = progress;
rd.fromUser = fromUser;
+ rd.animate = animate;
return rd;
}
@@ -1281,26 +1296,21 @@ public class ProgressBar extends View {
}
private synchronized void doRefreshProgress(int id, int progress, boolean fromUser,
- boolean callBackToApp) {
- float scale = mMax > 0 ? (float) progress / (float) mMax : 0;
- final Drawable d = mCurrentDrawable;
- if (d != null) {
- Drawable progressDrawable = null;
-
- if (d instanceof LayerDrawable) {
- progressDrawable = ((LayerDrawable) d).findDrawableByLayerId(id);
- if (progressDrawable != null && canResolveLayoutDirection()) {
- progressDrawable.setLayoutDirection(getLayoutDirection());
- }
- }
-
- final int level = (int) (scale * MAX_LEVEL);
- (progressDrawable != null ? progressDrawable : d).setLevel(level);
+ boolean callBackToApp, boolean animate) {
+ final float scale = mMax > 0 ? progress / (float) mMax : 0;
+ final boolean isPrimary = id == R.id.progress;
+
+ if (isPrimary && animate) {
+ final ObjectAnimator animator = ObjectAnimator.ofFloat(this, VISUAL_PROGRESS, scale);
+ animator.setAutoCancel(true);
+ animator.setDuration(PROGRESS_ANIM_DURATION);
+ animator.setInterpolator(PROGRESS_ANIM_INTERPOLATOR);
+ animator.start();
} else {
- invalidate();
+ setVisualProgress(id, scale);
}
- if (callBackToApp && id == R.id.progress) {
+ if (isPrimary && callBackToApp) {
onProgressRefresh(scale, fromUser, progress);
}
}
@@ -1311,15 +1321,51 @@ public class ProgressBar extends View {
}
}
- private synchronized void refreshProgress(int id, int progress, boolean fromUser) {
+ /**
+ * Sets the visual state of a progress indicator.
+ *
+ * @param id the identifier of the progress indicator
+ * @param progress the visual progress in the range [0...1]
+ */
+ private void setVisualProgress(int id, float progress) {
+ mVisualProgress = progress;
+
+ Drawable d = mCurrentDrawable;
+
+ if (d instanceof LayerDrawable) {
+ d = ((LayerDrawable) d).findDrawableByLayerId(id);
+ }
+
+ if (d != null) {
+ final int level = (int) (progress * MAX_LEVEL);
+ d.setLevel(level);
+ } else {
+ invalidate();
+ }
+
+ onVisualProgressChanged(id, progress);
+ }
+
+ /**
+ * Called when the visual state of a progress indicator changes.
+ *
+ * @param id the identifier of the progress indicator
+ * @param progress the visual progress in the range [0...1]
+ */
+ void onVisualProgressChanged(int id, float progress) {
+ // Stub method.
+ }
+
+ private synchronized void refreshProgress(int id, int progress, boolean fromUser,
+ boolean animate) {
if (mUiThreadId == Thread.currentThread().getId()) {
- doRefreshProgress(id, progress, fromUser, true);
+ doRefreshProgress(id, progress, fromUser, true, animate);
} else {
if (mRefreshProgressRunnable == null) {
mRefreshProgressRunnable = new RefreshProgressRunnable();
}
- final RefreshData rd = RefreshData.obtain(id, progress, fromUser);
+ final RefreshData rd = RefreshData.obtain(id, progress, fromUser, animate);
mRefreshData.add(rd);
if (mAttached && !mRefreshIsPosted) {
post(mRefreshProgressRunnable);
@@ -1329,8 +1375,8 @@ public class ProgressBar extends View {
}
/**
- * <p>Set the current progress to the specified value. Does not do anything
- * if the progress bar is in indeterminate mode.</p>
+ * Sets the current progress to the specified value. Does not do anything
+ * if the progress bar is in indeterminate mode.
*
* @param progress the new progress, between 0 and {@link #getMax()}
*
@@ -1341,11 +1387,26 @@ public class ProgressBar extends View {
*/
@android.view.RemotableViewMethod
public synchronized void setProgress(int progress) {
- setProgress(progress, false);
+ setProgressInternal(progress, false, false);
+ }
+
+ /**
+ * Sets the current progress to the specified value, optionally animating
+ * between the current and target values.
+ * <p>
+ * Animation does not affect the result of {@link #getProgress()}, which
+ * will return the target value immediately after this method is called.
+ *
+ * @param progress the new progress value, between 0 and {@link #getMax()}
+ * @param animate {@code true} to animate between the current and target
+ * values or {@code false} to not animate
+ */
+ public void setProgress(int progress, boolean animate) {
+ setProgressInternal(progress, false, animate);
}
@android.view.RemotableViewMethod
- synchronized boolean setProgress(int progress, boolean fromUser) {
+ synchronized boolean setProgressInternal(int progress, boolean fromUser, boolean animate) {
if (mIndeterminate) {
// Not applicable.
return false;
@@ -1359,7 +1420,7 @@ public class ProgressBar extends View {
}
mProgress = progress;
- refreshProgress(R.id.progress, mProgress, fromUser);
+ refreshProgress(R.id.progress, mProgress, fromUser, animate);
return true;
}
@@ -1391,7 +1452,7 @@ public class ProgressBar extends View {
if (secondaryProgress != mSecondaryProgress) {
mSecondaryProgress = secondaryProgress;
- refreshProgress(R.id.secondaryProgress, mSecondaryProgress, false);
+ refreshProgress(R.id.secondaryProgress, mSecondaryProgress, false, false);
}
}
@@ -1464,7 +1525,7 @@ public class ProgressBar extends View {
if (mProgress > max) {
mProgress = max;
}
- refreshProgress(R.id.progress, mProgress, false);
+ refreshProgress(R.id.progress, mProgress, false, false);
}
}
@@ -1847,7 +1908,7 @@ public class ProgressBar extends View {
final int count = mRefreshData.size();
for (int i = 0; i < count; i++) {
final RefreshData rd = mRefreshData.get(i);
- doRefreshProgress(rd.id, rd.progress, rd.fromUser, true);
+ doRefreshProgress(rd.id, rd.progress, rd.fromUser, true, rd.animate);
rd.recycle();
}
mRefreshData.clear();
@@ -1956,4 +2017,23 @@ public class ProgressBar extends View {
boolean mHasSecondaryProgressTint;
boolean mHasSecondaryProgressTintMode;
}
+
+ /**
+ * Property wrapper around the visual state of the {@code progress} functionality
+ * handled by the {@link ProgressBar#setProgress(int, boolean)} method. This does
+ * not correspond directly to the actual progress -- only the visual state.
+ */
+ private final FloatProperty<ProgressBar> VISUAL_PROGRESS =
+ new FloatProperty<ProgressBar>("visual_progress") {
+ @Override
+ public void setValue(ProgressBar object, float value) {
+ object.setVisualProgress(R.id.progress, value);
+ object.mVisualProgress = value;
+ }
+
+ @Override
+ public Float get(ProgressBar object) {
+ return object.mVisualProgress;
+ }
+ };
}
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/android/widget/Switch.java b/core/java/android/widget/Switch.java
index 6f3a711c8aff..434516da1346 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -1387,7 +1387,7 @@ public class Switch extends CompoundButton {
mTrackDrawable.jumpToCurrentState();
}
- if (mPositionAnimator != null && mPositionAnimator.isRunning()) {
+ if (mPositionAnimator != null && mPositionAnimator.isStarted()) {
mPositionAnimator.end();
mPositionAnimator = null;
}
diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java
index 2365b4850161..61ef6dc9d231 100644
--- a/core/java/android/widget/TimePickerClockDelegate.java
+++ b/core/java/android/widget/TimePickerClockDelegate.java
@@ -22,7 +22,6 @@ import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
-import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.SpannableStringBuilder;
@@ -32,7 +31,6 @@ import android.text.style.TtsSpan;
import android.util.AttributeSet;
import android.util.Log;
import android.util.StateSet;
-import android.util.TypedValue;
import android.view.HapticFeedbackConstants;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
@@ -66,10 +64,8 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate impl
// Also NOT a real index, just used for keyboard mode.
private static final int ENABLE_PICKER_INDEX = 3;
- private static final int[] ATTRS_TEXT_COLOR = new int[] {
- com.android.internal.R.attr.textColor};
- private static final int[] ATTRS_DISABLED_ALPHA = new int[] {
- com.android.internal.R.attr.disabledAlpha};
+ private static final int[] ATTRS_TEXT_COLOR = new int[] {R.attr.textColor};
+ private static final int[] ATTRS_DISABLED_ALPHA = new int[] {R.attr.disabledAlpha};
// LayoutLib relies on these constants. Change TimePickerClockDelegate_Delegate if
// modifying these.
diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java
index 471ea9b0031e..acbf5eb8d699 100644
--- a/core/java/android/widget/Toolbar.java
+++ b/core/java/android/widget/Toolbar.java
@@ -98,6 +98,32 @@ import java.util.List;
* <p>In modern Android UIs developers should lean more on a visually distinct color scheme for
* toolbars than on their application icon. The use of application icon plus title as a standard
* layout is discouraged on API 21 devices and newer.</p>
+ *
+ * @attr ref android.R.styleable#Toolbar_buttonGravity
+ * @attr ref android.R.styleable#Toolbar_collapseContentDescription
+ * @attr ref android.R.styleable#Toolbar_collapseIcon
+ * @attr ref android.R.styleable#Toolbar_contentInsetEnd
+ * @attr ref android.R.styleable#Toolbar_contentInsetLeft
+ * @attr ref android.R.styleable#Toolbar_contentInsetRight
+ * @attr ref android.R.styleable#Toolbar_contentInsetStart
+ * @attr ref android.R.styleable#Toolbar_gravity
+ * @attr ref android.R.styleable#Toolbar_logo
+ * @attr ref android.R.styleable#Toolbar_logoDescription
+ * @attr ref android.R.styleable#Toolbar_maxButtonHeight
+ * @attr ref android.R.styleable#Toolbar_navigationContentDescription
+ * @attr ref android.R.styleable#Toolbar_navigationIcon
+ * @attr ref android.R.styleable#Toolbar_popupTheme
+ * @attr ref android.R.styleable#Toolbar_subtitle
+ * @attr ref android.R.styleable#Toolbar_subtitleTextAppearance
+ * @attr ref android.R.styleable#Toolbar_subtitleTextColor
+ * @attr ref android.R.styleable#Toolbar_title
+ * @attr ref android.R.styleable#Toolbar_titleMargin
+ * @attr ref android.R.styleable#Toolbar_titleMarginBottom
+ * @attr ref android.R.styleable#Toolbar_titleMarginEnd
+ * @attr ref android.R.styleable#Toolbar_titleMarginStart
+ * @attr ref android.R.styleable#Toolbar_titleMarginTop
+ * @attr ref android.R.styleable#Toolbar_titleTextAppearance
+ * @attr ref android.R.styleable#Toolbar_titleTextColor
*/
public class Toolbar extends ViewGroup {
private static final String TAG = "Toolbar";
@@ -203,7 +229,7 @@ public class Toolbar extends ViewGroup {
mGravity = a.getInteger(R.styleable.Toolbar_gravity, mGravity);
mButtonGravity = a.getInteger(R.styleable.Toolbar_buttonGravity, Gravity.TOP);
mTitleMarginStart = mTitleMarginEnd = mTitleMarginTop = mTitleMarginBottom =
- a.getDimensionPixelOffset(R.styleable.Toolbar_titleMargins, 0);
+ a.getDimensionPixelOffset(R.styleable.Toolbar_titleMargin, 0);
final int marginStart = a.getDimensionPixelOffset(R.styleable.Toolbar_titleMarginStart, -1);
if (marginStart >= 0) {
@@ -321,6 +347,116 @@ public class Toolbar extends ViewGroup {
return mPopupTheme;
}
+ /**
+ * Sets the title margin.
+ *
+ * @param start the starting title margin in pixels
+ * @param top the top title margin in pixels
+ * @param end the ending title margin in pixels
+ * @param bottom the bottom title margin in pixels
+ * @see #getTitleMarginStart()
+ * @see #getTitleMarginTop()
+ * @see #getTitleMarginEnd()
+ * @see #getTitleMarginBottom()
+ * @attr ref android.R.styleable#Toolbar_titleMargin
+ */
+ public void setTitleMargin(int start, int top, int end, int bottom) {
+ mTitleMarginStart = start;
+ mTitleMarginTop = top;
+ mTitleMarginEnd = end;
+ mTitleMarginBottom = bottom;
+
+ requestLayout();
+ }
+
+ /**
+ * @return the starting title margin in pixels
+ * @see #setTitleMarginStart(int)
+ * @attr ref android.R.styleable#Toolbar_titleMarginStart
+ */
+ public int getTitleMarginStart() {
+ return mTitleMarginStart;
+ }
+
+ /**
+ * Sets the starting title margin in pixels.
+ *
+ * @param margin the starting title margin in pixels
+ * @see #getTitleMarginStart()
+ * @attr ref android.R.styleable#Toolbar_titleMarginStart
+ */
+ public void setTitleMarginStart(int margin) {
+ mTitleMarginStart = margin;
+
+ requestLayout();
+ }
+
+ /**
+ * @return the top title margin in pixels
+ * @see #setTitleMarginTop(int)
+ * @attr ref android.R.styleable#Toolbar_titleMarginTop
+ */
+ public int getTitleMarginTop() {
+ return mTitleMarginTop;
+ }
+
+ /**
+ * Sets the top title margin in pixels.
+ *
+ * @param margin the top title margin in pixels
+ * @see #getTitleMarginTop()
+ * @attr ref android.R.styleable#Toolbar_titleMarginTop
+ */
+ public void setTitleMarginTop(int margin) {
+ mTitleMarginTop = margin;
+
+ requestLayout();
+ }
+
+ /**
+ * @return the ending title margin in pixels
+ * @see #setTitleMarginEnd(int)
+ * @attr ref android.R.styleable#Toolbar_titleMarginEnd
+ */
+ public int getTitleMarginEnd() {
+ return mTitleMarginEnd;
+ }
+
+ /**
+ * Sets the ending title margin in pixels.
+ *
+ * @param margin the ending title margin in pixels
+ * @see #getTitleMarginEnd()
+ * @attr ref android.R.styleable#Toolbar_titleMarginEnd
+ */
+ public void setTitleMarginEnd(int margin) {
+ mTitleMarginEnd = margin;
+
+ requestLayout();
+ }
+
+ /**
+ * @return the bottom title margin in pixels
+ * @see #setTitleMarginBottom(int)
+ * @attr ref android.R.styleable#Toolbar_titleMarginBottom
+ */
+ public int getTitleMarginBottom() {
+ return mTitleMarginBottom;
+ }
+
+ /**
+ * Sets the bottom title margin in pixels.
+ *
+ * @param margin the bottom title margin in pixels
+ * @see #getTitleMarginBottom()
+ * @attr ref android.R.styleable#Toolbar_titleMarginBottom
+ */
+ public void setTitleMarginBottom(int margin) {
+ mTitleMarginBottom = margin;
+
+ requestLayout();
+ }
+
@Override
public void onRtlPropertiesChanged(@ResolvedLayoutDir int layoutDirection) {
super.onRtlPropertiesChanged(layoutDirection);
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 5b19edfabbe6..2172b5c57893 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -647,7 +647,8 @@ public class ChooserActivity extends ResolverActivity {
@Override
public CharSequence getExtendedInfo() {
- return mSourceInfo != null ? mSourceInfo.getExtendedInfo() : null;
+ // ChooserTargets have badge icons, so we won't show the extended info to disambiguate.
+ return null;
}
@Override
@@ -740,9 +741,8 @@ public class ChooserActivity extends ResolverActivity {
@Override
public boolean showsExtendedInfo(TargetInfo info) {
- // Reserve space to show extended info if any one of the items in the adapter has
- // extended info. This keeps grid item sizes uniform.
- return hasExtendedInfo();
+ // We have badges so we don't need this text shown.
+ return false;
}
@Override
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 9272193af54a..ef9d1cebff57 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -896,6 +896,7 @@ public class ResolverActivity extends Activity {
private final ResolveInfo mResolveInfo;
private final CharSequence mDisplayLabel;
private Drawable mDisplayIcon;
+ private Drawable mBadge;
private final CharSequence mExtendedInfo;
private final Intent mResolvedIntent;
private final List<Intent> mSourceIntents = new ArrayList<>();
@@ -940,7 +941,25 @@ public class ResolverActivity extends Activity {
}
public Drawable getBadgeIcon() {
- return null;
+ // We only expose a badge if we have extended info.
+ // The badge is a higher-priority disambiguation signal
+ // but we don't need one if we wouldn't show extended info at all.
+ if (TextUtils.isEmpty(getExtendedInfo())) {
+ return null;
+ }
+
+ if (mBadge == null && mResolveInfo != null && mResolveInfo.activityInfo != null
+ && mResolveInfo.activityInfo.applicationInfo != null) {
+ if (mResolveInfo.activityInfo.icon == 0 || mResolveInfo.activityInfo.icon
+ == mResolveInfo.activityInfo.applicationInfo.icon) {
+ // Badging an icon with exactly the same icon is silly.
+ // If the activityInfo icon resid is 0 it will fall back
+ // to the application's icon, making it a match.
+ return null;
+ }
+ mBadge = mResolveInfo.activityInfo.applicationInfo.loadIcon(mPm);
+ }
+ return mBadge;
}
@Override
@@ -1378,8 +1397,8 @@ public class ResolverActivity extends Activity {
} else {
mHasExtendedInfo = true;
boolean usePkg = false;
- CharSequence startApp = ro.getResolveInfoAt(0).activityInfo.applicationInfo
- .loadLabel(mPm);
+ final ApplicationInfo ai = ro.getResolveInfoAt(0).activityInfo.applicationInfo;
+ final CharSequence startApp = ai.loadLabel(mPm);
if (startApp == null) {
usePkg = true;
}
diff --git a/core/java/com/android/internal/inputmethod/InputMethodUtils.java b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
index a4ef00afdf02..01ac22e3c4fd 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodUtils.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
@@ -793,6 +793,24 @@ public class InputMethodUtils {
return imeMap;
}
+ @NonNull
+ public static String buildInputMethodsAndSubtypesString(
+ @NonNull final ArrayMap<String, ArraySet<String>> map) {
+ // we want to use the canonical InputMethodSettings implementation,
+ // so we convert data structures first.
+ List<Pair<String, ArrayList<String>>> imeMap = new ArrayList<>(4);
+ for (ArrayMap.Entry<String, ArraySet<String>> entry : map.entrySet()) {
+ final String imeName = entry.getKey();
+ final ArraySet<String> subtypeSet = entry.getValue();
+ final ArrayList<String> subtypes = new ArrayList<>(2);
+ if (subtypeSet != null) {
+ subtypes.addAll(subtypeSet);
+ }
+ imeMap.add(new Pair<>(imeName, subtypes));
+ }
+ return InputMethodSettings.buildInputMethodsSettingString(imeMap);
+ }
+
/**
* Utility class for putting and getting settings for InputMethod
* TODO: Move all putters and getters of settings to this class.
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index 4f4d3e0faa44..f178c8cf7ece 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -338,7 +338,7 @@ public final class BatteryStatsHelper {
}
if (mCpuPowerCalculator == null) {
- mCpuPowerCalculator = new CpuPowerCalculator();
+ mCpuPowerCalculator = new CpuPowerCalculator(mPowerProfile);
}
mCpuPowerCalculator.reset();
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 4ff786987028..e39bf607e53e 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 = 130 + (USE_OLD_HISTORY ? 1000 : 0);
+ private static final int VERSION = 131 + (USE_OLD_HISTORY ? 1000 : 0);
// Maximum number of items we will record in the history.
private static final int MAX_HISTORY_ITEMS = 2000;
@@ -118,8 +118,6 @@ public final class BatteryStatsImpl extends BatteryStats {
// in to one common name.
private static final int MAX_WAKELOCKS_PER_UID = 100;
- private static int sNumSpeedSteps;
-
private final JournaledFile mFile;
public final AtomicFile mCheckinFile;
public final AtomicFile mDailyFile;
@@ -133,7 +131,7 @@ public final class BatteryStatsImpl extends BatteryStats {
private final KernelWakelockStats mTmpWakelockStats = new KernelWakelockStats();
private final KernelUidCpuTimeReader mKernelUidCpuTimeReader = new KernelUidCpuTimeReader();
- private final KernelCpuSpeedReader mKernelCpuSpeedReader = new KernelCpuSpeedReader();
+ private KernelCpuSpeedReader[] mKernelCpuSpeedReaders;
public interface BatteryCallback {
public void batteryNeedsCpuUpdate();
@@ -4411,7 +4409,7 @@ public final class BatteryStatsImpl extends BatteryStats {
LongSamplingCounter mUserCpuTime = new LongSamplingCounter(mOnBatteryTimeBase);
LongSamplingCounter mSystemCpuTime = new LongSamplingCounter(mOnBatteryTimeBase);
LongSamplingCounter mCpuPower = new LongSamplingCounter(mOnBatteryTimeBase);
- LongSamplingCounter[] mSpeedBins;
+ LongSamplingCounter[][] mCpuClusterSpeed;
/**
* The statistics we have collected for this uid's wake locks.
@@ -4470,7 +4468,6 @@ public final class BatteryStatsImpl extends BatteryStats {
mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED,
mWifiMulticastTimers, mOnBatteryTimeBase);
mProcessStateTimer = new StopwatchTimer[NUM_PROCESS_STATE];
- mSpeedBins = new LongSamplingCounter[getCpuSpeedSteps()];
}
@Override
@@ -5008,10 +5005,18 @@ public final class BatteryStatsImpl extends BatteryStats {
}
@Override
- public long getTimeAtCpuSpeed(int step, int which) {
- if (step >= 0 && step < mSpeedBins.length) {
- if (mSpeedBins[step] != null) {
- return mSpeedBins[step].getCountLocked(which);
+ public long getTimeAtCpuSpeed(int cluster, int step, int which) {
+ if (mCpuClusterSpeed != null) {
+ if (cluster >= 0 && cluster < mCpuClusterSpeed.length) {
+ final LongSamplingCounter[] cpuSpeeds = mCpuClusterSpeed[cluster];
+ if (cpuSpeeds != null) {
+ if (step >= 0 && step < cpuSpeeds.length) {
+ final LongSamplingCounter c = cpuSpeeds[step];
+ if (c != null) {
+ return c.getCountLocked(which);
+ }
+ }
+ }
}
}
return 0;
@@ -5128,10 +5133,16 @@ public final class BatteryStatsImpl extends BatteryStats {
mUserCpuTime.reset(false);
mSystemCpuTime.reset(false);
mCpuPower.reset(false);
- for (int i = 0; i < mSpeedBins.length; i++) {
- LongSamplingCounter c = mSpeedBins[i];
- if (c != null) {
- c.reset(false);
+
+ if (mCpuClusterSpeed != null) {
+ for (LongSamplingCounter[] speeds : mCpuClusterSpeed) {
+ if (speeds != null) {
+ for (LongSamplingCounter speed : speeds) {
+ if (speed != null) {
+ speed.reset(false);
+ }
+ }
+ }
}
}
@@ -5280,10 +5291,16 @@ public final class BatteryStatsImpl extends BatteryStats {
mUserCpuTime.detach();
mSystemCpuTime.detach();
mCpuPower.detach();
- for (int i = 0; i < mSpeedBins.length; i++) {
- LongSamplingCounter c = mSpeedBins[i];
- if (c != null) {
- c.detach();
+
+ if (mCpuClusterSpeed != null) {
+ for (LongSamplingCounter[] cpuSpeeds : mCpuClusterSpeed) {
+ if (cpuSpeeds != null) {
+ for (LongSamplingCounter c : cpuSpeeds) {
+ if (c != null) {
+ c.detach();
+ }
+ }
+ }
}
}
}
@@ -5461,15 +5478,27 @@ public final class BatteryStatsImpl extends BatteryStats {
mSystemCpuTime.writeToParcel(out);
mCpuPower.writeToParcel(out);
- out.writeInt(mSpeedBins.length);
- for (int i = 0; i < mSpeedBins.length; i++) {
- LongSamplingCounter c = mSpeedBins[i];
- if (c != null) {
- out.writeInt(1);
- c.writeToParcel(out);
- } else {
- out.writeInt(0);
+ if (mCpuClusterSpeed != null) {
+ out.writeInt(1);
+ out.writeInt(mCpuClusterSpeed.length);
+ for (LongSamplingCounter[] cpuSpeeds : mCpuClusterSpeed) {
+ if (cpuSpeeds != null) {
+ out.writeInt(1);
+ out.writeInt(cpuSpeeds.length);
+ for (LongSamplingCounter c : cpuSpeeds) {
+ if (c != null) {
+ out.writeInt(1);
+ c.writeToParcel(out);
+ } else {
+ out.writeInt(0);
+ }
+ }
+ } else {
+ out.writeInt(0);
+ }
}
+ } else {
+ out.writeInt(0);
}
}
@@ -5653,13 +5682,32 @@ public final class BatteryStatsImpl extends BatteryStats {
mSystemCpuTime = new LongSamplingCounter(mOnBatteryTimeBase, in);
mCpuPower = new LongSamplingCounter(mOnBatteryTimeBase, in);
- int bins = in.readInt();
- int steps = getCpuSpeedSteps();
- mSpeedBins = new LongSamplingCounter[bins >= steps ? bins : steps];
- for (int i = 0; i < bins; i++) {
- if (in.readInt() != 0) {
- mSpeedBins[i] = new LongSamplingCounter(mOnBatteryTimeBase, in);
+ if (in.readInt() != 0) {
+ int numCpuClusters = in.readInt();
+ if (mPowerProfile != null && mPowerProfile.getNumCpuClusters() != numCpuClusters) {
+ throw new ParcelFormatException("Incompatible number of cpu clusters");
+ }
+
+ mCpuClusterSpeed = new LongSamplingCounter[numCpuClusters][];
+ for (int cluster = 0; cluster < numCpuClusters; cluster++) {
+ if (in.readInt() != 0) {
+ int numSpeeds = in.readInt();
+ if (mPowerProfile != null &&
+ mPowerProfile.getNumSpeedStepsInCpuCluster(cluster) != numSpeeds) {
+ throw new ParcelFormatException("Incompatible number of cpu speeds");
+ }
+
+ final LongSamplingCounter[] cpuSpeeds = new LongSamplingCounter[numSpeeds];
+ mCpuClusterSpeed[cluster] = cpuSpeeds;
+ for (int speed = 0; speed < numSpeeds; speed++) {
+ if (in.readInt() != 0) {
+ cpuSpeeds[speed] = new LongSamplingCounter(mOnBatteryTimeBase, in);
+ }
+ }
+ }
}
+ } else {
+ mCpuClusterSpeed = null;
}
}
@@ -6874,6 +6922,19 @@ public final class BatteryStatsImpl extends BatteryStats {
public void setPowerProfile(PowerProfile profile) {
synchronized (this) {
mPowerProfile = profile;
+
+ // We need to initialize the KernelCpuSpeedReaders to read from
+ // the first cpu of each core. Once we have the PowerProfile, we have access to this
+ // information.
+ final int numClusters = mPowerProfile.getNumCpuClusters();
+ mKernelCpuSpeedReaders = new KernelCpuSpeedReader[numClusters];
+ int firstCpuOfCluster = 0;
+ for (int i = 0; i < numClusters; i++) {
+ final int numSpeedSteps = mPowerProfile.getNumSpeedStepsInCpuCluster(i);
+ mKernelCpuSpeedReaders[i] = new KernelCpuSpeedReader(firstCpuOfCluster,
+ numSpeedSteps);
+ firstCpuOfCluster += mPowerProfile.getNumCoresInCpuCluster(i);
+ }
}
}
@@ -6881,10 +6942,6 @@ public final class BatteryStatsImpl extends BatteryStats {
mCallback = cb;
}
- public void setNumSpeedSteps(int steps) {
- if (sNumSpeedSteps == 0) sNumSpeedSteps = steps;
- }
-
public void setRadioScanningTimeout(long timeout) {
if (mPhoneSignalScanningTimer != null) {
mPhoneSignalScanningTimer.setTimeout(timeout);
@@ -7987,6 +8044,10 @@ public final class BatteryStatsImpl extends BatteryStats {
* wakelocks. If the screen is on, we just assign the actual cpu time an app used.
*/
public void updateCpuTimeLocked() {
+ if (mPowerProfile == null) {
+ return;
+ }
+
if (DEBUG_ENERGY_CPU) {
Slog.d(TAG, "!Cpu updating!");
}
@@ -7997,9 +8058,11 @@ public final class BatteryStatsImpl extends BatteryStats {
// If no app is holding a wakelock, then the distribution is normal.
final int wakelockWeight = 50;
- // Read the time spent at various cpu frequencies.
- final int cpuSpeedSteps = getCpuSpeedSteps();
- final long[] cpuSpeeds = mKernelCpuSpeedReader.readDelta();
+ // Read the time spent for each cluster at various cpu frequencies.
+ final long[][] clusterSpeeds = new long[mKernelCpuSpeedReaders.length][];
+ for (int cluster = 0; cluster < mKernelCpuSpeedReaders.length; cluster++) {
+ clusterSpeeds[cluster] = mKernelCpuSpeedReaders[cluster].readDelta();
+ }
int numWakelocks = 0;
@@ -8072,11 +8135,28 @@ public final class BatteryStatsImpl extends BatteryStats {
// Add the cpu speeds to this UID. These are used as a ratio
// for computing the power this UID used.
- for (int i = 0; i < cpuSpeedSteps; i++) {
- if (u.mSpeedBins[i] == null) {
- u.mSpeedBins[i] = new LongSamplingCounter(mOnBatteryTimeBase);
+ final int numClusters = mPowerProfile.getNumCpuClusters();
+ if (u.mCpuClusterSpeed == null || u.mCpuClusterSpeed.length !=
+ numClusters) {
+ u.mCpuClusterSpeed = new LongSamplingCounter[numClusters][];
+ }
+
+ for (int cluster = 0; cluster < clusterSpeeds.length; cluster++) {
+ final int speedsInCluster = mPowerProfile.getNumSpeedStepsInCpuCluster(
+ cluster);
+ if (u.mCpuClusterSpeed[cluster] == null || speedsInCluster !=
+ u.mCpuClusterSpeed[cluster].length) {
+ u.mCpuClusterSpeed[cluster] =
+ new LongSamplingCounter[speedsInCluster];
+ }
+
+ final LongSamplingCounter[] cpuSpeeds = u.mCpuClusterSpeed[cluster];
+ for (int speed = 0; speed < clusterSpeeds[cluster].length; speed++) {
+ if (cpuSpeeds[speed] == null) {
+ cpuSpeeds[speed] = new LongSamplingCounter(mOnBatteryTimeBase);
+ }
+ cpuSpeeds[speed].addCountLocked(clusterSpeeds[cluster][speed]);
}
- u.mSpeedBins[i].addCountLocked(cpuSpeeds[i]);
}
}
});
@@ -8776,11 +8856,6 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
- @Override
- public int getCpuSpeedSteps() {
- return sNumSpeedSteps;
- }
-
/**
* Retrieve the statistics object for a particular uid, creating if needed.
*/
@@ -9216,11 +9291,6 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
- sNumSpeedSteps = in.readInt();
- if (sNumSpeedSteps < 0 || sNumSpeedSteps > 100) {
- throw new ParcelFormatException("Bad speed steps in data: " + sNumSpeedSteps);
- }
-
final int NU = in.readInt();
if (NU > 10000) {
throw new ParcelFormatException("File corrupt: too many uids " + NU);
@@ -9304,17 +9374,33 @@ public final class BatteryStatsImpl extends BatteryStats {
u.mSystemCpuTime.readSummaryFromParcelLocked(in);
u.mCpuPower.readSummaryFromParcelLocked(in);
- int NSB = in.readInt();
- if (NSB > 100) {
- throw new ParcelFormatException("File corrupt: too many speed bins " + NSB);
- }
+ if (in.readInt() != 0) {
+ final int numClusters = in.readInt();
+ if (mPowerProfile != null && mPowerProfile.getNumCpuClusters() != numClusters) {
+ throw new ParcelFormatException("Incompatible cpu cluster arrangement");
+ }
- u.mSpeedBins = new LongSamplingCounter[NSB];
- for (int i=0; i<NSB; i++) {
- if (in.readInt() != 0) {
- u.mSpeedBins[i] = new LongSamplingCounter(mOnBatteryTimeBase);
- u.mSpeedBins[i].readSummaryFromParcelLocked(in);
+ 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) {
+ u.mCpuClusterSpeed[cluster] = new LongSamplingCounter[NSB];
+ for (int speed = 0; speed < NSB; speed++) {
+ if (in.readInt() != 0) {
+ u.mCpuClusterSpeed[cluster][speed] = new LongSamplingCounter(
+ mOnBatteryTimeBase);
+ u.mCpuClusterSpeed[cluster][speed].readSummaryFromParcelLocked(in);
+ }
+ }
+ }
}
+ } else {
+ u.mCpuClusterSpeed = null;
}
int NW = in.readInt();
@@ -9531,7 +9617,6 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
- out.writeInt(sNumSpeedSteps);
final int NU = mUidStats.size();
out.writeInt(NU);
for (int iu = 0; iu < NU; iu++) {
@@ -9640,15 +9725,27 @@ public final class BatteryStatsImpl extends BatteryStats {
u.mSystemCpuTime.writeSummaryFromParcelLocked(out);
u.mCpuPower.writeSummaryFromParcelLocked(out);
- out.writeInt(u.mSpeedBins.length);
- for (int i = 0; i < u.mSpeedBins.length; i++) {
- LongSamplingCounter speedBin = u.mSpeedBins[i];
- if (speedBin != null) {
- out.writeInt(1);
- speedBin.writeSummaryFromParcelLocked(out);
- } else {
- out.writeInt(0);
+ if (u.mCpuClusterSpeed != null) {
+ out.writeInt(1);
+ out.writeInt(u.mCpuClusterSpeed.length);
+ for (LongSamplingCounter[] cpuSpeeds : u.mCpuClusterSpeed) {
+ if (cpuSpeeds != null) {
+ out.writeInt(1);
+ out.writeInt(cpuSpeeds.length);
+ for (LongSamplingCounter c : cpuSpeeds) {
+ if (c != null) {
+ out.writeInt(1);
+ c.writeSummaryFromParcelLocked(out);
+ } else {
+ out.writeInt(0);
+ }
+ }
+ } else {
+ out.writeInt(0);
+ }
}
+ } else {
+ out.writeInt(0);
}
final ArrayMap<String, Uid.Wakelock> wakeStats = u.mWakelockStats.getMap();
@@ -9897,8 +9994,6 @@ public final class BatteryStatsImpl extends BatteryStats {
mFlashlightTurnedOnTimers.clear();
mCameraTurnedOnTimers.clear();
- sNumSpeedSteps = in.readInt();
-
int numUids = in.readInt();
mUidStats.clear();
for (int i = 0; i < numUids; i++) {
@@ -10037,8 +10132,6 @@ public final class BatteryStatsImpl extends BatteryStats {
out.writeInt(0);
}
- out.writeInt(sNumSpeedSteps);
-
if (inclUids) {
int size = mUidStats.size();
out.writeInt(size);
diff --git a/core/java/com/android/internal/os/CpuPowerCalculator.java b/core/java/com/android/internal/os/CpuPowerCalculator.java
index d62f7a689157..8417856d16d5 100644
--- a/core/java/com/android/internal/os/CpuPowerCalculator.java
+++ b/core/java/com/android/internal/os/CpuPowerCalculator.java
@@ -22,12 +22,47 @@ import android.util.Log;
public class CpuPowerCalculator extends PowerCalculator {
private static final String TAG = "CpuPowerCalculator";
private static final boolean DEBUG = BatteryStatsHelper.DEBUG;
+ private final PowerProfile mProfile;
+
+ public CpuPowerCalculator(PowerProfile profile) {
+ mProfile = profile;
+ }
@Override
public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
long rawUptimeUs, int statsType) {
+
app.cpuTimeMs = (u.getUserCpuTimeUs(statsType) + u.getSystemCpuTimeUs(statsType)) / 1000;
- app.cpuPowerMah = (double) u.getCpuPowerMaUs(statsType) / (60.0 * 60.0 * 1000.0 * 1000.0);
+
+ // Aggregate total time spent on each cluster.
+ long totalTime = 0;
+ final int numClusters = mProfile.getNumCpuClusters();
+ for (int cluster = 0; cluster < numClusters; cluster++) {
+ final int speedsForCluster = mProfile.getNumSpeedStepsInCpuCluster(cluster);
+ for (int speed = 0; speed < speedsForCluster; speed++) {
+ totalTime += u.getTimeAtCpuSpeed(cluster, speed, statsType);
+ }
+ }
+ totalTime = Math.max(totalTime, 1);
+
+ double cpuPowerMaMs = 0;
+ for (int cluster = 0; cluster < numClusters; cluster++) {
+ final int speedsForCluster = mProfile.getNumSpeedStepsInCpuCluster(cluster);
+ for (int speed = 0; speed < speedsForCluster; speed++) {
+ final double ratio = (double) u.getTimeAtCpuSpeed(cluster, speed, statsType) /
+ totalTime;
+ final double cpuSpeedStepPower = ratio * app.cpuTimeMs *
+ mProfile.getAveragePowerForCpu(cluster, speed);
+ if (DEBUG && ratio != 0) {
+ Log.d(TAG, "UID " + u.getUid() + ": CPU cluster #" + cluster + " step #"
+ + speed + " ratio=" + BatteryStatsHelper.makemAh(ratio) + " power="
+ + BatteryStatsHelper.makemAh(cpuSpeedStepPower / (60 * 60 * 1000)));
+ }
+ cpuPowerMaMs += cpuSpeedStepPower;
+ }
+ }
+ app.cpuPowerMah = cpuPowerMaMs / (60 * 60 * 1000);
+
if (DEBUG && (app.cpuTimeMs != 0 || app.cpuPowerMah != 0)) {
Log.d(TAG, "UID " + u.getUid() + ": CPU time=" + app.cpuTimeMs + " ms power="
+ BatteryStatsHelper.makemAh(app.cpuPowerMah));
diff --git a/core/java/com/android/internal/os/InstallerConnection.java b/core/java/com/android/internal/os/InstallerConnection.java
index dcc6a5e8cb33..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,31 +92,29 @@ public class InstallerConnection {
}
}
- public int dexopt(String apkPath, int uid, boolean isPublic,
- String instructionSet, int dexoptNeeded) {
- return dexopt(apkPath, uid, isPublic, "*", instructionSet, dexoptNeeded,
- false, false, null);
+ 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) {
+ 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(' ');
+ builder.append(dexFlags);
return execute(builder.toString());
}
diff --git a/core/java/com/android/internal/os/KernelCpuSpeedReader.java b/core/java/com/android/internal/os/KernelCpuSpeedReader.java
index c30df28c5c1f..5b776acf0cc8 100644
--- a/core/java/com/android/internal/os/KernelCpuSpeedReader.java
+++ b/core/java/com/android/internal/os/KernelCpuSpeedReader.java
@@ -24,8 +24,8 @@ import java.io.IOException;
import java.util.Arrays;
/**
- * Reads CPU time spent at various frequencies and provides a delta from the last call to
- * {@link #readDelta}. Each line in the proc file has the format:
+ * Reads CPU time of a specific core spent at various frequencies and provides a delta from the
+ * last call to {@link #readDelta}. Each line in the proc file has the format:
*
* freq time
*
@@ -33,12 +33,20 @@ import java.util.Arrays;
*/
public class KernelCpuSpeedReader {
private static final String TAG = "KernelCpuSpeedReader";
- private static final String sProcFile =
- "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state";
- private static final int MAX_SPEEDS = 60;
- private long[] mLastSpeedTimes = new long[MAX_SPEEDS];
- private long[] mDeltaSpeedTimes = new long[MAX_SPEEDS];
+ private final String mProcFile;
+ private final long[] mLastSpeedTimes;
+ private final long[] mDeltaSpeedTimes;
+
+ /**
+ * @param cpuNumber The cpu (cpu0, cpu1, etc) whose state to read.
+ */
+ public KernelCpuSpeedReader(int cpuNumber, int numSpeedSteps) {
+ mProcFile = String.format("/sys/devices/system/cpu/cpu%d/cpufreq/stats/time_in_state",
+ cpuNumber);
+ mLastSpeedTimes = new long[numSpeedSteps];
+ mDeltaSpeedTimes = new long[numSpeedSteps];
+ }
/**
* The returned array is modified in subsequent calls to {@link #readDelta}.
@@ -46,22 +54,28 @@ public class KernelCpuSpeedReader {
* {@link #readDelta}.
*/
public long[] readDelta() {
- try (BufferedReader reader = new BufferedReader(new FileReader(sProcFile))) {
+ try (BufferedReader reader = new BufferedReader(new FileReader(mProcFile))) {
TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter(' ');
String line;
int speedIndex = 0;
- while ((line = reader.readLine()) != null) {
+ while (speedIndex < mLastSpeedTimes.length && (line = reader.readLine()) != null) {
splitter.setString(line);
Long.parseLong(splitter.next());
// The proc file reports time in 1/100 sec, so convert to milliseconds.
long time = Long.parseLong(splitter.next()) * 10;
- mDeltaSpeedTimes[speedIndex] = time - mLastSpeedTimes[speedIndex];
+ if (time < mLastSpeedTimes[speedIndex]) {
+ // The stats reset when the cpu hotplugged. That means that the time
+ // we read is offset from 0, so the time is the delta.
+ mDeltaSpeedTimes[speedIndex] = time;
+ } else {
+ mDeltaSpeedTimes[speedIndex] = time - mLastSpeedTimes[speedIndex];
+ }
mLastSpeedTimes[speedIndex] = time;
speedIndex++;
}
} catch (IOException e) {
- Slog.e(TAG, "Failed to read cpu-freq", e);
+ Slog.e(TAG, "Failed to read cpu-freq: " + e.getMessage());
Arrays.fill(mDeltaSpeedTimes, 0);
}
return mDeltaSpeedTimes;
diff --git a/core/java/com/android/internal/os/KernelUidCpuTimeReader.java b/core/java/com/android/internal/os/KernelUidCpuTimeReader.java
index 0df78ed6a68d..5d3043cc8a02 100644
--- a/core/java/com/android/internal/os/KernelUidCpuTimeReader.java
+++ b/core/java/com/android/internal/os/KernelUidCpuTimeReader.java
@@ -137,7 +137,7 @@ public class KernelUidCpuTimeReader {
mLastPowerMaUs.put(uid, powerMaUs);
}
} catch (IOException e) {
- Slog.e(TAG, "Failed to read uid_cputime", e);
+ Slog.e(TAG, "Failed to read uid_cputime: " + e.getMessage());
}
mLastTimeReadUs = nowUs;
}
diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java
index 4ede8ddab3bc..aaa9f734aba8 100644
--- a/core/java/com/android/internal/os/PowerProfile.java
+++ b/core/java/com/android/internal/os/PowerProfile.java
@@ -59,6 +59,7 @@ public class PowerProfile {
/**
* Power consumption when CPU is in power collapse mode.
*/
+ @Deprecated
public static final String POWER_CPU_ACTIVE = "cpu.active";
/**
@@ -163,6 +164,7 @@ public class PowerProfile {
*/
public static final String POWER_CAMERA = "camera.avg";
+ @Deprecated
public static final String POWER_CPU_SPEEDS = "cpu.speeds";
/**
@@ -191,6 +193,7 @@ public class PowerProfile {
if (sPowerMap.size() == 0) {
readPowerValuesFromXml(context);
}
+ initCpuClusters();
}
private void readPowerValuesFromXml(Context context) {
@@ -249,7 +252,7 @@ public class PowerProfile {
}
// Now collect other config variables.
- int[] configResIds = new int[] {
+ int[] configResIds = new int[]{
com.android.internal.R.integer.config_bluetooth_idle_cur_ma,
com.android.internal.R.integer.config_bluetooth_rx_cur_ma,
com.android.internal.R.integer.config_bluetooth_tx_cur_ma,
@@ -260,7 +263,7 @@ public class PowerProfile {
com.android.internal.R.integer.config_wifi_operating_voltage_mv,
};
- String[] configResIdKeys = new String[] {
+ String[] configResIdKeys = new String[]{
POWER_BLUETOOTH_CONTROLLER_IDLE,
POWER_BLUETOOTH_CONTROLLER_RX,
POWER_BLUETOOTH_CONTROLLER_TX,
@@ -279,6 +282,69 @@ public class PowerProfile {
}
}
+ private CpuClusterKey[] mCpuClusters;
+
+ private static final String POWER_CPU_CLUSTER_CORE_COUNT = "cpu.clusters.cores";
+ private static final String POWER_CPU_CLUSTER_SPEED_PREFIX = "cpu.speeds.cluster";
+ private static final String POWER_CPU_CLUSTER_ACTIVE_PREFIX = "cpu.active.cluster";
+
+ @SuppressWarnings("deprecated")
+ private void initCpuClusters() {
+ // Figure out how many CPU clusters we're dealing with
+ final Object obj = sPowerMap.get(POWER_CPU_CLUSTER_CORE_COUNT);
+ if (obj == null || !(obj instanceof Double[])) {
+ // Default to single.
+ mCpuClusters = new CpuClusterKey[1];
+ mCpuClusters[0] = new CpuClusterKey(POWER_CPU_SPEEDS, POWER_CPU_ACTIVE, 1);
+
+ } else {
+ final Double[] array = (Double[]) obj;
+ mCpuClusters = new CpuClusterKey[array.length];
+ for (int cluster = 0; cluster < array.length; cluster++) {
+ int numCpusInCluster = (int) Math.round(array[cluster]);
+ mCpuClusters[cluster] = new CpuClusterKey(
+ POWER_CPU_CLUSTER_SPEED_PREFIX + cluster,
+ POWER_CPU_CLUSTER_ACTIVE_PREFIX + cluster,
+ numCpusInCluster);
+ }
+ }
+ }
+
+ public static class CpuClusterKey {
+ private final String timeKey;
+ private final String powerKey;
+ private final int numCpus;
+
+ private CpuClusterKey(String timeKey, String powerKey, int numCpus) {
+ this.timeKey = timeKey;
+ this.powerKey = powerKey;
+ this.numCpus = numCpus;
+ }
+ }
+
+ public int getNumCpuClusters() {
+ return mCpuClusters.length;
+ }
+
+ public int getNumCoresInCpuCluster(int index) {
+ return mCpuClusters[index].numCpus;
+ }
+
+ public int getNumSpeedStepsInCpuCluster(int index) {
+ Object value = sPowerMap.get(mCpuClusters[index].timeKey);
+ if (value != null && value instanceof Double[]) {
+ return ((Double[])value).length;
+ }
+ return 1; // Only one speed
+ }
+
+ public double getAveragePowerForCpu(int cluster, int step) {
+ if (cluster >= 0 && cluster < mCpuClusters.length) {
+ return getAveragePower(mCpuClusters[cluster].powerKey, step);
+ }
+ return 0;
+ }
+
/**
* Returns the average current in mA consumed by the subsystem, or the given
* default value if the subsystem has no recorded value.
@@ -344,16 +410,4 @@ public class PowerProfile {
public double getBatteryCapacity() {
return getAveragePower(POWER_BATTERY_CAPACITY);
}
-
- /**
- * Returns the number of speeds that the CPU can be run at.
- * @return
- */
- public int getNumSpeedSteps() {
- Object value = sPowerMap.get(POWER_CPU_SPEEDS);
- if (value != null && value instanceof Double[]) {
- return ((Double[])value).length;
- }
- return 1; // Only one speed
- }
}
diff --git a/core/java/com/android/internal/os/WrapperInit.java b/core/java/com/android/internal/os/WrapperInit.java
index 34ae58a287b2..c558cf8d1ee7 100644
--- a/core/java/com/android/internal/os/WrapperInit.java
+++ b/core/java/com/android/internal/os/WrapperInit.java
@@ -121,22 +121,4 @@ public class WrapperInit {
Zygote.appendQuotedShellArgs(command, args);
Zygote.execShell(command.toString());
}
-
- /**
- * Executes a standalone application with a wrapper command.
- * This method never returns.
- *
- * @param invokeWith The wrapper command.
- * @param classPath The class path.
- * @param className The class name to invoke.
- * @param args Arguments for the main() method of the specified class.
- */
- public static void execStandalone(String invokeWith, String classPath, String className,
- String[] args) {
- StringBuilder command = new StringBuilder(invokeWith);
- command.append(" /system/bin/dalvikvm -classpath '").append(classPath);
- command.append("' ").append(className);
- Zygote.appendQuotedShellArgs(command, args);
- Zygote.execShell(command.toString());
- }
}
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index af730978fd13..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);
+ installer.dexopt(classPathElement, Process.SYSTEM_UID, instructionSet,
+ dexoptNeeded, 0 /*dexFlags*/);
}
}
} catch (IOException ioe) {
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 7f01841d8afe..2e4d9b50b7be 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -71,6 +71,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;
@@ -170,6 +171,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
// This is the top-level view of the window, containing the window decor.
private DecorView mDecor;
+ // When we reuse decor views, we need to recreate the content root. This happens when the decor
+ // view is requested, so we need to force the recreating without introducing an infinite loop.
+ private boolean mForceDecorInstall = false;
+
// This is the non client decor view for the window, containing the caption and window control
// buttons. The visibility of this decor depends on the workspace and the window type.
// If the window type does not require such a view, this member might be null.
@@ -248,6 +253,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
private Drawable mBackgroundDrawable;
+ private boolean mLoadEleveation = true;
private float mElevation;
/** Whether window content should be clipped to the background outline. */
@@ -269,6 +275,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;
@@ -323,6 +330,16 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
mLayoutInflater = LayoutInflater.from(context);
}
+ public PhoneWindow(Context context, Window preservedWindow) {
+ this(context);
+ if (preservedWindow != null) {
+ mDecor = (DecorView) preservedWindow.getDecorView();
+ mElevation = preservedWindow.getElevation();
+ mLoadEleveation = false;
+ mForceDecorInstall = true;
+ }
+ }
+
@Override
public final void setContainer(Window container) {
super.setContainer(container);
@@ -463,6 +480,12 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
}
+ public void clearContentView() {
+ if (mNonClientDecorView.getChildCount() > 1) {
+ mNonClientDecorView.removeViewAt(1);
+ }
+ }
+
private void transitionTo(Scene scene) {
if (mContentScene == null) {
scene.enter();
@@ -1102,6 +1125,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
mContextMenuHelper.dismiss();
mContextMenuHelper = null;
}
+ if (mContextMenuPopupHelper != null) {
+ mContextMenuPopupHelper.dismiss();
+ mContextMenuPopupHelper = null;
+ }
}
@Override
@@ -1396,6 +1423,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
@Override
+ public float getElevation() {
+ return mElevation;
+ }
+
+ @Override
public final void setClipToOutline(boolean clipToOutline) {
mClipToOutline = clipToOutline;
if (mDecor != null) {
@@ -1992,7 +2024,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
@Override
public final View getDecorView() {
- if (mDecor == null) {
+ if (mDecor == null || mForceDecorInstall) {
installDecor();
}
return mDecor;
@@ -2820,6 +2852,29 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
@Override
+ public boolean showContextMenuForChild(View originalView, float x, float y) {
+ // Reuse the context menu builder
+ if (mContextMenu == null) {
+ mContextMenu = new ContextMenuBuilder(getContext());
+ mContextMenu.setCallback(mContextMenuCallback);
+ } else {
+ mContextMenu.clearAll();
+ }
+
+ final MenuPopupHelper helper = mContextMenu.showPopup(
+ getContext(), originalView, x, y);
+ if (helper != null) {
+ helper.setCallback(mContextMenuCallback);
+ } else if (mContextMenuPopupHelper != null) {
+ // No menu to show, but if we have a menu currently showing it just became blank.
+ // Close it.
+ mContextMenuPopupHelper.dismiss();
+ }
+ mContextMenuPopupHelper = helper;
+ return helper != null;
+ }
+
+ @Override
public ActionMode startActionModeForChild(View originalView,
ActionMode.Callback callback) {
return startActionModeForChild(originalView, callback, ActionMode.TYPE_PRIMARY);
@@ -3960,7 +4015,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
+ Integer.toHexString(mFrameResource));
}
}
- mElevation = a.getDimension(R.styleable.Window_windowElevation, 0);
+ if (mLoadEleveation) {
+ mElevation = a.getDimension(R.styleable.Window_windowElevation, 0);
+ }
mClipToOutline = a.getBoolean(R.styleable.Window_windowClipToOutline, false);
mTextColor = a.getColor(R.styleable.Window_textColor, Color.TRANSPARENT);
}
@@ -4032,8 +4089,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
mNonClientDecorView = createNonClientDecorView();
View in = mLayoutInflater.inflate(layoutResource, null);
if (mNonClientDecorView != null) {
- decor.addView(mNonClientDecorView,
- new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
+ if (mNonClientDecorView.getParent() == null) {
+ decor.addView(mNonClientDecorView,
+ new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
+ }
mNonClientDecorView.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
} else {
decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
@@ -4096,6 +4155,14 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
// Free floating overlapping windows require a non client decor with a caption and shadow..
private NonClientDecorView createNonClientDecorView() {
NonClientDecorView nonClientDecorView = null;
+ for (int i = mDecor.getChildCount() - 1; i >= 0 && nonClientDecorView == null; i--) {
+ View view = mDecor.getChildAt(i);
+ if (view instanceof NonClientDecorView) {
+ // The decor was most likely saved from a relaunch - so reuse it.
+ nonClientDecorView = (NonClientDecorView) view;
+ mDecor.removeViewAt(i);
+ }
+ }
final WindowManager.LayoutParams attrs = getAttributes();
boolean isApplication = attrs.type == TYPE_BASE_APPLICATION ||
attrs.type == TYPE_APPLICATION;
@@ -4106,21 +4173,22 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
mWorkspaceId < FIRST_DYNAMIC_STACK_ID) {
// Dependent on the brightness of the used title we either use the
// dark or the light button frame.
- TypedValue value = new TypedValue();
- getContext().getTheme().resolveAttribute(R.attr.colorPrimary, value, true);
- if (Color.luminance(value.data) < 0.5) {
- nonClientDecorView = (NonClientDecorView) mLayoutInflater.inflate(
- R.layout.non_client_decor_dark, null);
- } else {
- nonClientDecorView = (NonClientDecorView) mLayoutInflater.inflate(
- R.layout.non_client_decor_light, null);
+ if (nonClientDecorView == null) {
+ TypedValue value = new TypedValue();
+ getContext().getTheme().resolveAttribute(R.attr.colorPrimary, value, true);
+ if (Color.luminance(value.data) < 0.5) {
+ nonClientDecorView = (NonClientDecorView) mLayoutInflater.inflate(
+ R.layout.non_client_decor_dark, null);
+ } else {
+ nonClientDecorView = (NonClientDecorView) mLayoutInflater.inflate(
+ R.layout.non_client_decor_light, null);
+ }
}
nonClientDecorView.setPhoneWindow(this, hasNonClientDecor(mWorkspaceId),
nonClientDecorHasShadow(mWorkspaceId));
}
// Tell the decor if it has a visible non client decor.
- mDecor.enableNonClientDecor(nonClientDecorView != null &&
- hasNonClientDecor(mWorkspaceId));
+ mDecor.enableNonClientDecor(nonClientDecorView != null && hasNonClientDecor(mWorkspaceId));
return nonClientDecorView;
}
@@ -4131,6 +4199,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
private void installDecor() {
+ mForceDecorInstall = false;
if (mDecor == null) {
mDecor = generateDecor(-1);
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
@@ -5307,4 +5376,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
// TODO(skuhne): Add side by side mode here to add a decor.
return workspaceId == FREEFORM_WORKSPACE_STACK_ID;
}
+
+ @Override
+ public boolean hasNonClientDecorView() {
+ return mNonClientDecorView != null;
+ }
}
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/FloatingActionMode.java b/core/java/com/android/internal/view/FloatingActionMode.java
index 44df0ce89133..b44baa2b8422 100644
--- a/core/java/com/android/internal/view/FloatingActionMode.java
+++ b/core/java/com/android/internal/view/FloatingActionMode.java
@@ -35,7 +35,7 @@ import java.util.Arrays;
public class FloatingActionMode extends ActionMode {
private static final int MAX_HIDE_DURATION = 3000;
- private static final int MOVING_HIDE_DELAY = 300;
+ private static final int MOVING_HIDE_DELAY = 50;
private final Context mContext;
private final ActionMode.Callback2 mCallback;
@@ -181,7 +181,6 @@ public class FloatingActionMode extends ActionMode {
// Content rect is moving.
mOriginatingView.removeCallbacks(mMovingOff);
mFloatingToolbarVisibilityHelper.setMoving(true);
- mFloatingToolbarVisibilityHelper.updateToolbarVisibility();
mOriginatingView.postDelayed(mMovingOff, MOVING_HIDE_DELAY);
mFloatingToolbar.setContentRect(mContentRectOnScreen);
@@ -189,9 +188,9 @@ public class FloatingActionMode extends ActionMode {
}
} else {
mFloatingToolbarVisibilityHelper.setOutOfBounds(true);
- mFloatingToolbarVisibilityHelper.updateToolbarVisibility();
mContentRectOnScreen.setEmpty();
}
+ mFloatingToolbarVisibilityHelper.updateToolbarVisibility();
mPreviousContentRectOnScreen.set(mContentRectOnScreen);
}
diff --git a/core/java/com/android/internal/view/IDropPermissionHolder.aidl b/core/java/com/android/internal/view/IDropPermissionHolder.aidl
new file mode 100644
index 000000000000..e60ab0e516e5
--- /dev/null
+++ b/core/java/com/android/internal/view/IDropPermissionHolder.aidl
@@ -0,0 +1,26 @@
+/*
+** Copyright 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.view;
+
+/**
+ * Interface to allow a drop receiver to request permissions for URIs passed along with ClipData
+ * contained in DragEvent.
+ */
+interface IDropPermissionHolder {
+ void grant();
+ void revoke();
+}
diff --git a/core/java/com/android/internal/view/menu/CascadingMenuPopup.java b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
index 4c829a240e70..293e2ade7229 100644
--- a/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
+++ b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
@@ -10,18 +10,26 @@ import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Rect;
+import android.os.Handler;
import android.os.Parcelable;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.ViewTreeObserver;
+import android.view.View.OnAttachStateChangeListener;
import android.view.View.OnKeyListener;
-import android.widget.AdapterView;
+import android.view.ViewTreeObserver.OnGlobalLayoutListener;
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;
@@ -30,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 {}
@@ -39,21 +47,151 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl
private static final int HORIZ_POSITION_LEFT = 0;
private static final int HORIZ_POSITION_RIGHT = 1;
+ private static final int SUBMENU_TIMEOUT_MS = 200;
+
private final Context mContext;
private final int mMenuMaxWidth;
private final int mPopupStyleAttr;
private final int mPopupStyleRes;
private final boolean mOverflowOnly;
private final int mLayoutDirection;
+ private final Handler mSubMenuHoverHandler;
+
+ private final OnGlobalLayoutListener mGlobalLayoutListener = new OnGlobalLayoutListener() {
+ @Override
+ public void onGlobalLayout() {
+ if (isShowing()) {
+ final View anchor = mShownAnchorView;
+ if (anchor == null || !anchor.isShown()) {
+ dismiss();
+ } else if (isShowing()) {
+ // Recompute window sizes and positions.
+ for (MenuPopupWindow popup : mPopupWindows) {
+ popup.show();
+ }
+ }
+ }
+ }
+ };
+
+ private final OnAttachStateChangeListener mAttachStateChangeListener =
+ new OnAttachStateChangeListener() {
+ @Override
+ public void onViewAttachedToWindow(View v) {
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View v) {
+ if (mTreeObserver != null) {
+ if (!mTreeObserver.isAlive()) {
+ mTreeObserver = v.getViewTreeObserver();
+ }
+ mTreeObserver.removeGlobalOnLayoutListener(mGlobalLayoutListener);
+ }
+ v.removeOnAttachStateChangeListener(this);
+ }
+ };
+
+ private final MenuItemHoverListener mMenuItemHoverListener = new MenuItemHoverListener() {
+ @Override
+ public void onItemHovered(MenuBuilder menu, int position) {
+ int menuIndex = -1;
+ for (int i = 0; i < mListViews.size(); i++) {
+ final MenuDropDownListView view = (MenuDropDownListView) mListViews.get(i);
+ final MenuAdapter adapter = toMenuAdapter(view.getAdapter());
+
+ if (adapter.getAdapterMenu() == menu) {
+ menuIndex = i;
+ break;
+ }
+ }
+
+ if (menuIndex == -1) {
+ return;
+ }
+
+ final MenuDropDownListView view = (MenuDropDownListView) mListViews.get(menuIndex);
+ final ListMenuItemView selectedItemView = (ListMenuItemView) view.getSelectedView();
+
+ if (selectedItemView != null && selectedItemView.isEnabled()
+ && selectedItemView.getItemData().hasSubMenu()) {
+ // If the currently selected item corresponds to a submenu, schedule to open the
+ // submenu on a timeout.
+
+ mSubMenuHoverHandler.removeCallbacksAndMessages(null);
+ mSubMenuHoverHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ // Make sure the submenu item is still the one selected.
+ if (view.getSelectedView() == selectedItemView
+ && selectedItemView.isEnabled()
+ && selectedItemView.getItemData().hasSubMenu()) {
+ // Close any other submenus that might be open at the current or
+ // a deeper level.
+ int nextIndex = mListViews.indexOf(view) + 1;
+ if (nextIndex < mListViews.size()) {
+ MenuAdapter nextSubMenuAdapter =
+ toMenuAdapter(mListViews.get(nextIndex).getAdapter());
+ // Disable exit animation, to prevent overlapping fading out
+ // submenus.
+ mPopupWindows.get(nextIndex).setExitTransition(null);
+ nextSubMenuAdapter.getAdapterMenu().close();
+ }
+
+ // Then open the selected submenu.
+ view.performItemClick(
+ selectedItemView,
+ view.getSelectedItemPosition(),
+ view.getSelectedItemId());
+ }
+ }
+ }, SUBMENU_TIMEOUT_MS);
+ } else if (menuIndex + 1 < mListViews.size()) {
+ // If the currently selected item does NOT corresponds to a submenu, check if there
+ // is a submenu already open that is one level deeper. If so, schedule to close it
+ // on a timeout.
+
+ final MenuDropDownListView nextView =
+ (MenuDropDownListView) mListViews.get(menuIndex + 1);
+ final MenuAdapter nextAdapter = toMenuAdapter(nextView.getAdapter());
+
+ mSubMenuHoverHandler.removeCallbacksAndMessages(null);
+ mSubMenuHoverHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ // Make sure the menu wasn't already closed by something else and that
+ // it wasn't re-hovered by the user since this was scheduled.
+ int nextMenuIndex = mListViews.indexOf(nextView);
+
+ if (nextMenuIndex != -1 && nextView.getSelectedView() == null) {
+ // Disable exit animation, to prevent overlapping fading out submenus.
+ for (int i = nextMenuIndex; i < mPopupWindows.size(); i++) {
+ final MenuPopupWindow popupWindow = mPopupWindows.get(i);
+ popupWindow.setExitTransition(null);
+ popupWindow.setAnimationStyle(0);
+ }
+ nextAdapter.getAdapterMenu().close();
+ }
+ }
+ }, SUBMENU_TIMEOUT_MS);
+ }
+ }
+ };
private int mDropDownGravity = Gravity.NO_GRAVITY;
- private View mAnchor;
+ private View mAnchorView;
+ private View mShownAnchorView;
private List<DropDownListView> mListViews;
private List<MenuPopupWindow> mPopupWindows;
+ private int mLastPosition;
+ private List<Integer> mPositions;
private List<int[]> mOffsets;
- private int mPreferredPosition;
+ private int mInitXOffset;
+ private int mInitYOffset;
private boolean mForceShowIcon;
+ private boolean mShowTitle;
private Callback mPresenterCallback;
+ private ViewTreeObserver mTreeObserver;
private PopupWindow.OnDismissListener mOnDismissListener;
/**
@@ -64,7 +202,7 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl
public CascadingMenuPopup(Context context, View anchor, int popupStyleAttr,
int popupStyleRes, boolean overflowOnly) {
mContext = Preconditions.checkNotNull(context);
- mAnchor = Preconditions.checkNotNull(anchor);
+ mAnchorView = Preconditions.checkNotNull(anchor);
mPopupStyleAttr = popupStyleAttr;
mPopupStyleRes = popupStyleRes;
mOverflowOnly = overflowOnly;
@@ -74,14 +212,15 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl
final Resources res = context.getResources();
final Configuration config = res.getConfiguration();
mLayoutDirection = config.getLayoutDirection();
- mPreferredPosition = mLayoutDirection == View.LAYOUT_DIRECTION_RTL ? HORIZ_POSITION_LEFT :
- HORIZ_POSITION_RIGHT;
+ mLastPosition = getInitialMenuPosition();
mMenuMaxWidth = Math.max(res.getDisplayMetrics().widthPixels / 2,
res.getDimensionPixelSize(com.android.internal.R.dimen.config_prefDialogWidth));
mPopupWindows = new ArrayList<MenuPopupWindow>();
mListViews = new ArrayList<DropDownListView>();
mOffsets = new ArrayList<int[]>();
+ mPositions = new ArrayList<Integer>();
+ mSubMenuHoverHandler = new Handler();
}
@Override
@@ -92,12 +231,12 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl
private MenuPopupWindow createPopupWindow() {
MenuPopupWindow popupWindow = new MenuPopupWindow(
mContext, null, mPopupStyleAttr, mPopupStyleRes);
+ popupWindow.setHoverListener(mMenuItemHoverListener);
popupWindow.setOnItemClickListener(this);
popupWindow.setOnDismissListener(this);
- popupWindow.setAnchorView(mAnchor);
+ popupWindow.setAnchorView(mAnchorView);
popupWindow.setDropDownGravity(mDropDownGravity);
popupWindow.setModal(true);
- popupWindow.setTouchModal(false);
return popupWindow;
}
@@ -114,7 +253,35 @@ 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;
+ if (mShownAnchorView != null) {
+ final boolean addGlobalListener = mTreeObserver == null;
+ mTreeObserver = mShownAnchorView.getViewTreeObserver(); // Refresh to latest
+ if (addGlobalListener) {
+ mTreeObserver.addOnGlobalLayoutListener(mGlobalLayoutListener);
+ }
+ mShownAnchorView.addOnAttachStateChangeListener(mAttachStateChangeListener);
}
}
@@ -131,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();
@@ -146,6 +307,16 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl
}
/**
+ * Determines the proper initial menu position for the current LTR/RTL configuration.
+ * @return The initial position.
+ */
+ @HorizPosition
+ private int getInitialMenuPosition() {
+ return mLayoutDirection == View.LAYOUT_DIRECTION_RTL ? HORIZ_POSITION_LEFT :
+ HORIZ_POSITION_RIGHT;
+ }
+
+ /**
* Determines whether the next submenu (of the given width) should display on the right or on
* the left of the most recent menu.
*
@@ -160,9 +331,9 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl
lastListView.getLocationOnScreen(screenLocation);
final Rect displayFrame = new Rect();
- mAnchor.getWindowVisibleDisplayFrame(displayFrame);
+ mShownAnchorView.getWindowVisibleDisplayFrame(displayFrame);
- if (mPreferredPosition == HORIZ_POSITION_RIGHT) {
+ if (mLastPosition == HORIZ_POSITION_RIGHT) {
final int right = screenLocation[0] + lastListView.getWidth() + nextMenuWidth;
if (right > displayFrame.right) {
return HORIZ_POSITION_LEFT;
@@ -196,12 +367,13 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl
int y = 0;
if (addSubMenu) {
+ popupWindow.setTouchModal(false);
popupWindow.setEnterTransition(null);
ListView lastListView = mListViews.get(mListViews.size() - 1);
@HorizPosition int nextMenuPosition = getNextMenuPosition(menuWidth);
boolean showOnRight = nextMenuPosition == HORIZ_POSITION_RIGHT;
- mPreferredPosition = nextMenuPosition;
+ mLastPosition = nextMenuPosition;
int[] lastLocation = new int[2];
lastListView.getLocationOnScreen(lastLocation);
@@ -226,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);
@@ -238,11 +413,13 @@ 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};
mOffsets.add(offsets);
+ mPositions.add(mLastPosition);
}
/**
@@ -269,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();
}
}
}
@@ -278,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();
}
}
@@ -291,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;
@@ -315,11 +493,11 @@ 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;
- wasSelected = view.getSelectedItem() != null;
+ wasSelected = view.getSelectedView() != null;
}
// Once the menu has been found, remove it and all submenus beneath it from the
@@ -338,9 +516,11 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl
mListViews.subList(menuIndex, mListViews.size()).clear();
mOffsets.subList(menuIndex, mOffsets.size()).clear();
- // If there's still a menu open, refocus the new leaf [sub]menu.
- if (mListViews.size() > 0) {
- mListViews.get(mListViews.size() - 1).requestFocus();
+ mPositions.subList(menuIndex, mPositions.size()).clear();
+ if (mPositions.size() > 0) {
+ mLastPosition = mPositions.get(mPositions.size() - 1);
+ } else {
+ mLastPosition = getInitialMenuPosition();
}
}
@@ -352,6 +532,13 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl
}
if (mPopupWindows.size() == 0) {
+ if (mTreeObserver != null) {
+ if (mTreeObserver.isAlive()) {
+ mTreeObserver.removeGlobalOnLayoutListener(mGlobalLayoutListener);
+ }
+ mTreeObserver = null;
+ }
+ mShownAnchorView.removeOnAttachStateChangeListener(mAttachStateChangeListener);
// If every [sub]menu was dismissed, that means the whole thing was dismissed, so notify
// the owner.
mOnDismissListener.onDismiss();
@@ -379,7 +566,7 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl
@Override
public void setAnchorView(View anchor) {
- mAnchor = anchor;
+ mAnchorView = anchor;
}
@Override
@@ -391,4 +578,19 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl
public ListView getListView() {
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/MenuAdapter.java b/core/java/com/android/internal/view/menu/MenuAdapter.java
index 1e03b1f8b971..673cfd12d878 100644
--- a/core/java/com/android/internal/view/menu/MenuAdapter.java
+++ b/core/java/com/android/internal/view/menu/MenuAdapter.java
@@ -40,6 +40,10 @@ public class MenuAdapter extends BaseAdapter {
findExpandedIndex();
}
+ public boolean getForceShowIcon() {
+ return mForceShowIcon;
+ }
+
public void setForceShowIcon(boolean forceShow) {
mForceShowIcon = forceShow;
}
diff --git a/core/java/com/android/internal/view/menu/MenuItemImpl.java b/core/java/com/android/internal/view/menu/MenuItemImpl.java
index 08d4e8616795..624c9e24e945 100644
--- a/core/java/com/android/internal/view/menu/MenuItemImpl.java
+++ b/core/java/com/android/internal/view/menu/MenuItemImpl.java
@@ -149,7 +149,7 @@ public final class MenuItemImpl implements MenuItem {
return true;
}
- if (mMenu.dispatchMenuItemSelected(mMenu.getRootMenu(), this)) {
+ if (mMenu.dispatchMenuItemSelected(mMenu, this)) {
return true;
}
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 e0d7feefb1b0..e674eccd889d 100644
--- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java
+++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
@@ -16,10 +16,11 @@
package com.android.internal.view.menu;
+import com.android.internal.view.menu.MenuPresenter.Callback;
+
import android.content.Context;
import android.view.Gravity;
import android.view.View;
-import android.view.ViewTreeObserver;
import android.widget.PopupWindow;
/**
@@ -27,8 +28,7 @@ import android.widget.PopupWindow;
*
* @hide
*/
-public class MenuPopupHelper implements ViewTreeObserver.OnGlobalLayoutListener,
- PopupWindow.OnDismissListener, View.OnAttachStateChangeListener {
+public class MenuPopupHelper implements PopupWindow.OnDismissListener {
private final Context mContext;
private final MenuBuilder mMenu;
private final boolean mOverflowOnly;
@@ -37,9 +37,13 @@ public class MenuPopupHelper implements ViewTreeObserver.OnGlobalLayoutListener,
private View mAnchorView;
private MenuPopup mPopup;
- private ViewTreeObserver mTreeObserver;
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 ViewTreeObserver.OnGlobalLayoutListener,
}
public void setForceShowIcon(boolean forceShow) {
+ mForceShowIcon = forceShow;
mPopup.setForceShowIcon(forceShow);
}
@@ -99,6 +104,12 @@ public class MenuPopupHelper implements ViewTreeObserver.OnGlobalLayoutListener,
}
}
+ 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;
}
@@ -114,18 +125,45 @@ public class MenuPopupHelper implements ViewTreeObserver.OnGlobalLayoutListener,
return true;
}
- final View anchor = mAnchorView;
- if (anchor != null) {
- final boolean addGlobalListener = mTreeObserver == null;
- mTreeObserver = anchor.getViewTreeObserver(); // Refresh to latest
- if (addGlobalListener) mTreeObserver.addOnGlobalLayoutListener(this);
- anchor.addOnAttachStateChangeListener(this);
- mPopup.setAnchorView(anchor);
- mPopup.setGravity(mDropDownGravity);
- } else {
+ if (mAnchorView == null) {
+ 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.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.
// Not to worry -- the inner MenuPopup will call our own #onDismiss method after it's done
@@ -134,7 +172,6 @@ public class MenuPopupHelper implements ViewTreeObserver.OnGlobalLayoutListener,
mPopup.addMenu(mMenu);
mPopup.show();
- return true;
}
public void dismiss() {
@@ -146,45 +183,14 @@ public class MenuPopupHelper implements ViewTreeObserver.OnGlobalLayoutListener,
@Override
public void onDismiss() {
mPopup = null;
- if (mTreeObserver != null) {
- if (!mTreeObserver.isAlive()) mTreeObserver = mAnchorView.getViewTreeObserver();
- mTreeObserver.removeGlobalOnLayoutListener(this);
- mTreeObserver = null;
- }
- mAnchorView.removeOnAttachStateChangeListener(this);
}
public boolean isShowing() {
return mPopup != null && mPopup.isShowing();
}
- @Override
- public void onGlobalLayout() {
- if (isShowing()) {
- final View anchor = mAnchorView;
- if (anchor == null || !anchor.isShown()) {
- dismiss();
- } else if (isShowing()) {
- // Recompute window size and position
- mPopup.show();
- }
- }
- }
-
- @Override
- public void onViewAttachedToWindow(View v) {
- }
-
- @Override
- public void onViewDetachedFromWindow(View v) {
- if (mTreeObserver != null) {
- if (!mTreeObserver.isAlive()) mTreeObserver = v.getViewTreeObserver();
- mTreeObserver.removeGlobalOnLayoutListener(this);
- }
- v.removeOnAttachStateChangeListener(this);
- }
-
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 9a30ffafb75d..caee0d2d9a74 100644
--- a/core/java/com/android/internal/view/menu/StandardMenuPopup.java
+++ b/core/java/com/android/internal/view/menu/StandardMenuPopup.java
@@ -6,14 +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.widget.AdapterView;
+import android.view.ViewTreeObserver.OnGlobalLayoutListener;
+import android.view.ViewTreeObserver;
+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;
@@ -34,15 +37,53 @@ final class StandardMenuPopup extends MenuPopup implements OnDismissListener, On
private final int mPopupMaxWidth;
private final int mPopupStyleAttr;
private final int mPopupStyleRes;
+ // The popup window is final in order to couple its lifecycle to the lifecycle of the
+ // StandardMenuPopup.
+ private final MenuPopupWindow mPopup;
+
+ private final OnGlobalLayoutListener mGlobalLayoutListener = new OnGlobalLayoutListener() {
+ @Override
+ public void onGlobalLayout() {
+ if (isShowing()) {
+ final View anchor = mShownAnchorView;
+ if (anchor == null || !anchor.isShown()) {
+ dismiss();
+ } else if (isShowing()) {
+ // Recompute window size and position
+ mPopup.show();
+ }
+ }
+ }
+ };
+
+ private final OnAttachStateChangeListener mAttachStateChangeListener =
+ new OnAttachStateChangeListener() {
+ @Override
+ public void onViewAttachedToWindow(View v) {
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View v) {
+ if (mTreeObserver != null) {
+ if (!mTreeObserver.isAlive()) mTreeObserver = v.getViewTreeObserver();
+ mTreeObserver.removeGlobalOnLayoutListener(mGlobalLayoutListener);
+ }
+ v.removeOnAttachStateChangeListener(this);
+ }
+ };
private PopupWindow.OnDismissListener mOnDismissListener;
private View mAnchorView;
- private MenuPopupWindow mPopup;
+ private View mShownAnchorView;
private Callback mPresenterCallback;
+ private ViewTreeObserver mTreeObserver;
private ViewGroup mMeasureParent;
+ /** Whether the popup has been dismissed. Once dismissed, it cannot be opened again. */
+ private boolean mWasDismissed;
+
/** Whether the cached content width value is valid. */
private boolean mHasContentWidth;
@@ -51,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);
@@ -88,18 +133,26 @@ final class StandardMenuPopup extends MenuPopup implements OnDismissListener, On
return true;
}
+ if (mWasDismissed || mAnchorView == null) {
+ return false;
+ }
+
+ mShownAnchorView = mAnchorView;
+
mPopup.setOnDismissListener(this);
mPopup.setOnItemClickListener(this);
mPopup.setAdapter(mAdapter);
mPopup.setModal(true);
- final View anchor = mAnchorView;
- if (anchor != null) {
- mPopup.setAnchorView(anchor);
- mPopup.setDropDownGravity(mDropDownGravity);
- } else {
- return false;
+ final View anchor = mShownAnchorView;
+ final boolean addGlobalListener = mTreeObserver == null;
+ mTreeObserver = anchor.getViewTreeObserver(); // Refresh to latest
+ if (addGlobalListener) {
+ mTreeObserver.addOnGlobalLayoutListener(mGlobalLayoutListener);
}
+ anchor.addOnAttachStateChangeListener(mAttachStateChangeListener);
+ mPopup.setAnchorView(anchor);
+ mPopup.setDropDownGravity(mDropDownGravity);
if (!mHasContentWidth) {
mContentWidth = measureIndividualMenuWidth(
@@ -109,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;
}
@@ -129,26 +202,26 @@ 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.
}
@Override
public boolean isShowing() {
- return mPopup != null && mPopup.isShowing();
+ return !mWasDismissed && mPopup.isShowing();
}
@Override
public void onDismiss() {
- mPopup = null;
+ mWasDismissed = true;
mMenu.close();
+ if (mTreeObserver != null) {
+ if (!mTreeObserver.isAlive()) mTreeObserver = mShownAnchorView.getViewTreeObserver();
+ mTreeObserver.removeGlobalOnLayoutListener(mGlobalLayoutListener);
+ mTreeObserver = null;
+ }
+ mShownAnchorView.removeOnAttachStateChangeListener(mAttachStateChangeListener);
mOnDismissListener.onDismiss();
}
@@ -170,19 +243,10 @@ final class StandardMenuPopup extends MenuPopup implements OnDismissListener, On
public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
if (subMenu.hasVisibleItems()) {
MenuPopupHelper subPopup = new MenuPopupHelper(
- mContext, subMenu, mAnchorView, mOverflowOnly, mPopupStyleAttr, mPopupStyleRes);
+ mContext, subMenu, mShownAnchorView, mOverflowOnly, mPopupStyleAttr,
+ mPopupStyleRes);
subPopup.setCallback(mPresenterCallback);
-
- boolean preserveIconSpacing = false;
- final int count = subMenu.size();
- for (int i = 0; i < count; i++) {
- MenuItem childItem = subMenu.getItem(i);
- if (childItem.isVisible() && childItem.getIcon() != null) {
- preserveIconSpacing = true;
- break;
- }
- }
- subPopup.setForceShowIcon(preserveIconSpacing);
+ subPopup.setForceShowIcon(mAdapter.getForceShowIcon());
if (subPopup.tryShow()) {
if (mPresenterCallback != null) {
@@ -210,7 +274,6 @@ final class StandardMenuPopup extends MenuPopup implements OnDismissListener, On
return false;
}
-
@Override
public Parcelable onSaveInstanceState() {
return null;
@@ -243,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/view/menu/SubMenuBuilder.java b/core/java/com/android/internal/view/menu/SubMenuBuilder.java
index 92acf8cda8f5..cf741bf5bb02 100644
--- a/core/java/com/android/internal/view/menu/SubMenuBuilder.java
+++ b/core/java/com/android/internal/view/menu/SubMenuBuilder.java
@@ -73,7 +73,7 @@ public class SubMenuBuilder extends MenuBuilder implements SubMenu {
@Override
public MenuBuilder getRootMenu() {
- return mParentMenu;
+ return mParentMenu.getRootMenu();
}
@Override
diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java
index ca6fe619f528..2a25db6b64c4 100644
--- a/core/java/com/android/internal/widget/FloatingToolbar.java
+++ b/core/java/com/android/internal/widget/FloatingToolbar.java
@@ -1488,10 +1488,9 @@ public final class FloatingToolbar {
private static AnimatorSet createEnterAnimation(View view) {
AnimatorSet animation = new AnimatorSet();
animation.playTogether(
- ObjectAnimator.ofFloat(view, View.ALPHA, 0, 1).setDuration(200),
+ ObjectAnimator.ofFloat(view, View.ALPHA, 0, 1).setDuration(150),
// Make sure that view.x is always fixed throughout the duration of this animation.
ObjectAnimator.ofFloat(view, View.X, view.getX(), view.getX()));
- animation.setStartDelay(50);
return animation;
}
@@ -1506,7 +1505,7 @@ public final class FloatingToolbar {
View view, int startDelay, Animator.AnimatorListener listener) {
AnimatorSet animation = new AnimatorSet();
animation.playTogether(
- ObjectAnimator.ofFloat(view, View.ALPHA, 1, 0).setDuration(200));
+ ObjectAnimator.ofFloat(view, View.ALPHA, 1, 0).setDuration(100));
animation.setStartDelay(startDelay);
animation.addListener(listener);
return animation;
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 6a98ec70f92e..f7e9add58f21 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -1075,12 +1075,22 @@ public class LockPatternUtils {
* enter a pattern.
*/
public long getLockoutAttemptDeadline(int userId) {
- final long deadline = getLong(LOCKOUT_ATTEMPT_DEADLINE, 0L, userId);
+ 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 || deadline > (now + timeoutMs)) {
+ if (deadline < now) {
+ // timeout expired
+ setLong(LOCKOUT_ATTEMPT_DEADLINE, 0, userId);
+ setLong(LOCKOUT_ATTEMPT_TIMEOUT_MS, 0, userId);
return 0L;
}
+
+ if (deadline > (now + timeoutMs)) {
+ // device was rebooted, set new deadline
+ deadline = now + timeoutMs;
+ setLong(LOCKOUT_ATTEMPT_DEADLINE, deadline, userId);
+ }
+
return deadline;
}
diff --git a/core/java/com/android/server/LocalServices.java b/core/java/com/android/server/LocalServices.java
index 25dcb308b55a..9c632ea725a9 100644
--- a/core/java/com/android/server/LocalServices.java
+++ b/core/java/com/android/server/LocalServices.java
@@ -16,6 +16,8 @@
package com.android.server;
+import com.android.internal.annotations.VisibleForTesting;
+
import android.util.ArrayMap;
/**
@@ -57,4 +59,14 @@ public final class LocalServices {
sLocalServiceObjects.put(type, service);
}
}
+
+ /**
+ * Remove a service instance, must be only used in tests.
+ */
+ @VisibleForTesting
+ public static <T> void removeServiceForTest(Class<T> type) {
+ synchronized (sLocalServiceObjects) {
+ sLocalServiceObjects.remove(type);
+ }
+ }
}
diff --git a/core/java/com/android/server/backup/NotificationBackupHelper.java b/core/java/com/android/server/backup/NotificationBackupHelper.java
index 6f5c7e8149b4..0d225e87d77b 100644
--- a/core/java/com/android/server/backup/NotificationBackupHelper.java
+++ b/core/java/com/android/server/backup/NotificationBackupHelper.java
@@ -46,7 +46,8 @@ public class NotificationBackupHelper extends BlobBackupHelper {
try {
INotificationManager nm = INotificationManager.Stub.asInterface(
ServiceManager.getService("notification"));
- newPayload = nm.getBackupPayload(UserHandle.USER_OWNER);
+ // TODO: http://b/22388012
+ newPayload = nm.getBackupPayload(UserHandle.USER_SYSTEM);
} catch (Exception e) {
// Treat as no data
Slog.e(TAG, "Couldn't communicate with notification manager");
@@ -66,7 +67,8 @@ public class NotificationBackupHelper extends BlobBackupHelper {
try {
INotificationManager nm = INotificationManager.Stub.asInterface(
ServiceManager.getService("notification"));
- nm.applyRestore(payload, UserHandle.USER_OWNER);
+ // TODO: http://b/22388012
+ nm.applyRestore(payload, UserHandle.USER_SYSTEM);
} catch (Exception e) {
Slog.e(TAG, "Couldn't communicate with notification manager");
}
diff --git a/core/java/com/android/server/backup/PreferredActivityBackupHelper.java b/core/java/com/android/server/backup/PreferredActivityBackupHelper.java
index 458a2ca19d18..80636706a9a6 100644
--- a/core/java/com/android/server/backup/PreferredActivityBackupHelper.java
+++ b/core/java/com/android/server/backup/PreferredActivityBackupHelper.java
@@ -52,13 +52,14 @@ public class PreferredActivityBackupHelper extends BlobBackupHelper {
Slog.d(TAG, "Handling backup of " + key);
}
try {
+ // TODO: http://b/22388012
switch (key) {
case KEY_PREFERRED:
- return pm.getPreferredActivityBackup(UserHandle.USER_OWNER);
+ return pm.getPreferredActivityBackup(UserHandle.USER_SYSTEM);
case KEY_DEFAULT_APPS:
- return pm.getDefaultAppsBackup(UserHandle.USER_OWNER);
+ return pm.getDefaultAppsBackup(UserHandle.USER_SYSTEM);
case KEY_INTENT_VERIFICATION:
- return pm.getIntentFilterVerificationBackup(UserHandle.USER_OWNER);
+ return pm.getIntentFilterVerificationBackup(UserHandle.USER_SYSTEM);
default:
Slog.w(TAG, "Unexpected backup key " + key);
}
@@ -75,15 +76,16 @@ public class PreferredActivityBackupHelper extends BlobBackupHelper {
Slog.d(TAG, "Handling restore of " + key);
}
try {
+ // TODO: http://b/22388012
switch (key) {
case KEY_PREFERRED:
- pm.restorePreferredActivities(payload, UserHandle.USER_OWNER);
+ pm.restorePreferredActivities(payload, UserHandle.USER_SYSTEM);
break;
case KEY_DEFAULT_APPS:
- pm.restoreDefaultApps(payload, UserHandle.USER_OWNER);
+ pm.restoreDefaultApps(payload, UserHandle.USER_SYSTEM);
break;
case KEY_INTENT_VERIFICATION:
- pm.restoreIntentFilterVerification(payload, UserHandle.USER_OWNER);
+ pm.restoreIntentFilterVerification(payload, UserHandle.USER_SYSTEM);
break;
default:
Slog.w(TAG, "Unexpected restore key " + key);
diff --git a/core/java/com/android/server/backup/SystemBackupAgent.java b/core/java/com/android/server/backup/SystemBackupAgent.java
index f485460bddc3..234815fc901d 100644
--- a/core/java/com/android/server/backup/SystemBackupAgent.java
+++ b/core/java/com/android/server/backup/SystemBackupAgent.java
@@ -54,13 +54,15 @@ public class SystemBackupAgent extends BackupAgentHelper {
private static final String WALLPAPER_INFO_FILENAME = "wallpaper_info.xml";
// TODO: Will need to change if backing up non-primary user's wallpaper
+ // TODO: http://b/22388012
private static final String WALLPAPER_IMAGE_DIR =
- Environment.getUserSystemDirectory(UserHandle.USER_OWNER).getAbsolutePath();
+ Environment.getUserSystemDirectory(UserHandle.USER_SYSTEM).getAbsolutePath();
private static final String WALLPAPER_IMAGE = WallpaperBackupHelper.WALLPAPER_IMAGE;
// TODO: Will need to change if backing up non-primary user's wallpaper
+ // TODO: http://b/22388012
private static final String WALLPAPER_INFO_DIR =
- Environment.getUserSystemDirectory(UserHandle.USER_OWNER).getAbsolutePath();
+ Environment.getUserSystemDirectory(UserHandle.USER_SYSTEM).getAbsolutePath();
private static final String WALLPAPER_INFO = WallpaperBackupHelper.WALLPAPER_INFO;
// Use old keys to keep legacy data compatibility and avoid writing two wallpapers
private static final String WALLPAPER_IMAGE_KEY = WallpaperBackupHelper.WALLPAPER_IMAGE_KEY;
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index e4bc80013b9c..ffc69a93f106 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -217,7 +217,7 @@ static void com_android_internal_os_RuntimeInit_nativeSetExitWithoutCleanup(JNIE
/*
* JNI registration.
*/
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
{ "nativeFinishInit", "()V",
(void*) com_android_internal_os_RuntimeInit_nativeFinishInit },
{ "nativeZygoteInit", "()V",
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index fbe3ececc348..e6c7c2bcf9d7 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -1348,7 +1348,7 @@ static jlong Bitmap_refPixelRef(JNIEnv* env, jobject, jlong bitmapHandle) {
///////////////////////////////////////////////////////////////////////////////
-static JNINativeMethod gBitmapMethods[] = {
+static const JNINativeMethod gBitmapMethods[] = {
{ "nativeCreate", "([IIIIIIZ)Landroid/graphics/Bitmap;",
(void*)Bitmap_creator },
{ "nativeCopy", "(JIZ)Landroid/graphics/Bitmap;",
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 20a54e538ea8..28bc7fe47dd2 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -542,7 +542,7 @@ jobject decodeBitmap(JNIEnv* env, void* data, size_t size) {
///////////////////////////////////////////////////////////////////////////////
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
{ "nativeDecodeStream",
"(Ljava/io/InputStream;[BLandroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
(void*)nativeDecodeStream
@@ -569,7 +569,7 @@ static JNINativeMethod gMethods[] = {
},
};
-static JNINativeMethod gOptionsMethods[] = {
+static const JNINativeMethod gOptionsMethods[] = {
{ "requestCancel", "()V", (void*)nativeRequestCancel }
};
diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp
index 8535e6a8c975..2df3a4641aeb 100644
--- a/core/jni/android/graphics/BitmapRegionDecoder.cpp
+++ b/core/jni/android/graphics/BitmapRegionDecoder.cpp
@@ -47,7 +47,7 @@ public:
fHeight = height;
}
~SkBitmapRegionDecoder() {
- SkDELETE(fDecoder);
+ delete fDecoder;
}
bool decodeRegion(SkBitmap* bitmap, const SkIRect& rect,
@@ -72,7 +72,7 @@ static jobject createBitmapRegionDecoder(JNIEnv* env, SkStreamRewindable* stream
SkImageDecoder* decoder = SkImageDecoder::Factory(stream);
int width, height;
if (NULL == decoder) {
- SkDELETE(stream);
+ delete stream;
doThrowIOE(env, "Image format not supported");
return nullObjectReturn("SkImageDecoder::Factory returned null");
}
@@ -87,7 +87,7 @@ static jobject createBitmapRegionDecoder(JNIEnv* env, SkStreamRewindable* stream
snprintf(msg, sizeof(msg), "Image failed to decode using %s decoder",
decoder->getFormatName());
doThrowIOE(env, msg);
- SkDELETE(decoder);
+ delete decoder;
return nullObjectReturn("decoder->buildTileIndex returned false");
}
@@ -261,7 +261,7 @@ static void nativeClean(JNIEnv* env, jobject, jlong brdHandle) {
///////////////////////////////////////////////////////////////////////////////
-static JNINativeMethod gBitmapRegionDecoderMethods[] = {
+static const JNINativeMethod gBitmapRegionDecoderMethods[] = {
{ "nativeDecodeRegion",
"(JIIIILandroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
(void*)nativeDecodeRegion},
diff --git a/core/jni/android/graphics/Camera.cpp b/core/jni/android/graphics/Camera.cpp
index 036ece1cec28..6fcf6892d490 100644
--- a/core/jni/android/graphics/Camera.cpp
+++ b/core/jni/android/graphics/Camera.cpp
@@ -115,7 +115,7 @@ static jfloat Camera_dotWithNormal(JNIEnv* env, jobject obj,
/*
* JNI registration.
*/
-static JNINativeMethod gCameraMethods[] = {
+static const JNINativeMethod gCameraMethods[] = {
/* name, signature, funcPtr */
{ "nativeConstructor", "()V", (void*)Camera_constructor },
diff --git a/core/jni/android/graphics/CanvasProperty.cpp b/core/jni/android/graphics/CanvasProperty.cpp
index deb4971a8a01..728bc1c3677e 100644
--- a/core/jni/android/graphics/CanvasProperty.cpp
+++ b/core/jni/android/graphics/CanvasProperty.cpp
@@ -39,7 +39,7 @@ static jlong createPaint(JNIEnv* env, jobject clazz, jlong paintPtr) {
// JNI Glue
// ----------------------------------------------------------------------------
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
{ "nCreateFloat", "(F)J", (void*) createFloat },
{ "nCreatePaint", "(J)J", (void*) createPaint },
};
diff --git a/core/jni/android/graphics/ColorFilter.cpp b/core/jni/android/graphics/ColorFilter.cpp
index d03bcf0fe3ac..83fd07382fe0 100644
--- a/core/jni/android/graphics/ColorFilter.cpp
+++ b/core/jni/android/graphics/ColorFilter.cpp
@@ -57,19 +57,19 @@ public:
}
};
-static JNINativeMethod colorfilter_methods[] = {
+static const JNINativeMethod colorfilter_methods[] = {
{"destroyFilter", "(J)V", (void*) SkColorFilterGlue::finalizer}
};
-static JNINativeMethod porterduff_methods[] = {
+static const JNINativeMethod porterduff_methods[] = {
{ "native_CreatePorterDuffFilter", "(II)J", (void*) SkColorFilterGlue::CreatePorterDuffFilter },
};
-static JNINativeMethod lighting_methods[] = {
+static const JNINativeMethod lighting_methods[] = {
{ "native_CreateLightingFilter", "(II)J", (void*) SkColorFilterGlue::CreateLightingFilter },
};
-static JNINativeMethod colormatrix_methods[] = {
+static const JNINativeMethod colormatrix_methods[] = {
{ "nativeColorMatrixFilter", "([F)J", (void*) SkColorFilterGlue::CreateColorMatrixFilter },
};
diff --git a/core/jni/android/graphics/DrawFilter.cpp b/core/jni/android/graphics/DrawFilter.cpp
index 90ef6c0745cd..c1dc0dd025b6 100644
--- a/core/jni/android/graphics/DrawFilter.cpp
+++ b/core/jni/android/graphics/DrawFilter.cpp
@@ -97,11 +97,11 @@ public:
}
};
-static JNINativeMethod drawfilter_methods[] = {
+static const JNINativeMethod drawfilter_methods[] = {
{"nativeDestructor", "(J)V", (void*) SkDrawFilterGlue::finalizer}
};
-static JNINativeMethod paintflags_methods[] = {
+static const JNINativeMethod paintflags_methods[] = {
{"nativeConstructor","(II)J", (void*) SkDrawFilterGlue::CreatePaintFlagsDF}
};
diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp
index 38db76b0b183..dac6d96eb7df 100644
--- a/core/jni/android/graphics/FontFamily.cpp
+++ b/core/jni/android/graphics/FontFamily.cpp
@@ -124,7 +124,7 @@ static jboolean FontFamily_addFontFromAsset(JNIEnv* env, jobject, jlong familyPt
///////////////////////////////////////////////////////////////////////////////
-static JNINativeMethod gFontFamilyMethods[] = {
+static const JNINativeMethod gFontFamilyMethods[] = {
{ "nCreateFamily", "(Ljava/lang/String;I)J", (void*)FontFamily_create },
{ "nUnrefFamily", "(J)V", (void*)FontFamily_unref },
{ "nAddFont", "(JLjava/lang/String;)Z", (void*)FontFamily_addFont },
diff --git a/core/jni/android/graphics/Interpolator.cpp b/core/jni/android/graphics/Interpolator.cpp
index 3593d1a4ab32..fa28359281db 100644
--- a/core/jni/android/graphics/Interpolator.cpp
+++ b/core/jni/android/graphics/Interpolator.cpp
@@ -71,7 +71,7 @@ static jint Interpolator_timeToValues(JNIEnv* env, jobject clazz, jlong interpHa
/*
* JNI registration.
*/
-static JNINativeMethod gInterpolatorMethods[] = {
+static const JNINativeMethod gInterpolatorMethods[] = {
{ "nativeConstructor", "(II)J", (void*)Interpolator_constructor },
{ "nativeDestructor", "(J)V", (void*)Interpolator_destructor },
{ "nativeReset", "(JII)V", (void*)Interpolator_reset },
diff --git a/core/jni/android/graphics/MaskFilter.cpp b/core/jni/android/graphics/MaskFilter.cpp
index d65864312196..2b4a1abbd673 100644
--- a/core/jni/android/graphics/MaskFilter.cpp
+++ b/core/jni/android/graphics/MaskFilter.cpp
@@ -61,19 +61,19 @@ public:
}
};
-static JNINativeMethod gMaskFilterMethods[] = {
+static const JNINativeMethod gMaskFilterMethods[] = {
{ "nativeDestructor", "(J)V", (void*)SkMaskFilterGlue::destructor }
};
-static JNINativeMethod gBlurMaskFilterMethods[] = {
+static const JNINativeMethod gBlurMaskFilterMethods[] = {
{ "nativeConstructor", "(FI)J", (void*)SkMaskFilterGlue::createBlur }
};
-static JNINativeMethod gEmbossMaskFilterMethods[] = {
+static const JNINativeMethod gEmbossMaskFilterMethods[] = {
{ "nativeConstructor", "([FFFF)J", (void*)SkMaskFilterGlue::createEmboss }
};
-static JNINativeMethod gTableMaskFilterMethods[] = {
+static const JNINativeMethod gTableMaskFilterMethods[] = {
{ "nativeNewTable", "([B)J", (void*)SkMaskFilterGlue::createTable },
{ "nativeNewClip", "(II)J", (void*)SkMaskFilterGlue::createClipTable },
{ "nativeNewGamma", "(F)J", (void*)SkMaskFilterGlue::createGammaTable }
diff --git a/core/jni/android/graphics/Matrix.cpp b/core/jni/android/graphics/Matrix.cpp
index 101e2ba603e6..b0f3bb4b965a 100644
--- a/core/jni/android/graphics/Matrix.cpp
+++ b/core/jni/android/graphics/Matrix.cpp
@@ -302,7 +302,7 @@ public:
}
};
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
{"finalizer", "(J)V", (void*) SkMatrixGlue::finalizer},
{"native_create","(J)J", (void*) SkMatrixGlue::create},
diff --git a/core/jni/android/graphics/Movie.cpp b/core/jni/android/graphics/Movie.cpp
index d67ed10e9ef1..498c5902e5fd 100644
--- a/core/jni/android/graphics/Movie.cpp
+++ b/core/jni/android/graphics/Movie.cpp
@@ -135,7 +135,7 @@ static void movie_destructor(JNIEnv* env, jobject, jlong movieHandle) {
//////////////////////////////////////////////////////////////////////////////////////////////
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
{ "width", "()I", (void*)movie_width },
{ "height", "()I", (void*)movie_height },
{ "isOpaque", "()Z", (void*)movie_isOpaque },
diff --git a/core/jni/android/graphics/NinePatch.cpp b/core/jni/android/graphics/NinePatch.cpp
index 1c282623f455..3ccbb35cc960 100644
--- a/core/jni/android/graphics/NinePatch.cpp
+++ b/core/jni/android/graphics/NinePatch.cpp
@@ -108,7 +108,7 @@ public:
/////////////////////////////////////////////////////////////////////////////////////////
-static JNINativeMethod gNinePatchMethods[] = {
+static const JNINativeMethod gNinePatchMethods[] = {
{ "isNinePatchChunk", "([B)Z", (void*) SkNinePatchGlue::isNinePatchChunk },
{ "validateNinePatchChunk", "([B)J",
(void*) SkNinePatchGlue::validateNinePatchChunk },
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 988d13aa7ea8..520dc4fdb496 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -1095,7 +1095,7 @@ public:
};
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
{"finalizer", "(J)V", (void*) PaintGlue::finalizer},
{"native_init","()J", (void*) PaintGlue::init},
{"native_initWithPaint","(J)J", (void*) PaintGlue::initWithPaint},
diff --git a/core/jni/android/graphics/Path.cpp b/core/jni/android/graphics/Path.cpp
index dbd7c89805ab..2998c99a273e 100644
--- a/core/jni/android/graphics/Path.cpp
+++ b/core/jni/android/graphics/Path.cpp
@@ -475,7 +475,7 @@ public:
}
};
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
{"finalizer", "(J)V", (void*) SkPathGlue::finalizer},
{"init1","()J", (void*) SkPathGlue::init1},
{"init2","(J)J", (void*) SkPathGlue::init2},
diff --git a/core/jni/android/graphics/PathEffect.cpp b/core/jni/android/graphics/PathEffect.cpp
index 265944e216e2..b289b21a3d8b 100644
--- a/core/jni/android/graphics/PathEffect.cpp
+++ b/core/jni/android/graphics/PathEffect.cpp
@@ -69,31 +69,31 @@ public:
////////////////////////////////////////////////////////////////////////////////////////////////////////
-static JNINativeMethod gPathEffectMethods[] = {
+static const JNINativeMethod gPathEffectMethods[] = {
{ "nativeDestructor", "(J)V", (void*)SkPathEffectGlue::destructor }
};
-static JNINativeMethod gComposePathEffectMethods[] = {
+static const JNINativeMethod gComposePathEffectMethods[] = {
{ "nativeCreate", "(JJ)J", (void*)SkPathEffectGlue::Compose_constructor }
};
-static JNINativeMethod gSumPathEffectMethods[] = {
+static const JNINativeMethod gSumPathEffectMethods[] = {
{ "nativeCreate", "(JJ)J", (void*)SkPathEffectGlue::Sum_constructor }
};
-static JNINativeMethod gDashPathEffectMethods[] = {
+static const JNINativeMethod gDashPathEffectMethods[] = {
{ "nativeCreate", "([FF)J", (void*)SkPathEffectGlue::Dash_constructor }
};
-static JNINativeMethod gPathDashPathEffectMethods[] = {
+static const JNINativeMethod gPathDashPathEffectMethods[] = {
{ "nativeCreate", "(JFFI)J", (void*)SkPathEffectGlue::OneD_constructor }
};
-static JNINativeMethod gCornerPathEffectMethods[] = {
+static const JNINativeMethod gCornerPathEffectMethods[] = {
{ "nativeCreate", "(F)J", (void*)SkPathEffectGlue::Corner_constructor }
};
-static JNINativeMethod gDiscretePathEffectMethods[] = {
+static const JNINativeMethod gDiscretePathEffectMethods[] = {
{ "nativeCreate", "(FF)J", (void*)SkPathEffectGlue::Discrete_constructor }
};
diff --git a/core/jni/android/graphics/PathMeasure.cpp b/core/jni/android/graphics/PathMeasure.cpp
index fec5d9db3a6a..70e528d4be6f 100644
--- a/core/jni/android/graphics/PathMeasure.cpp
+++ b/core/jni/android/graphics/PathMeasure.cpp
@@ -143,7 +143,7 @@ public:
}
};
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
{"native_create", "(JZ)J", (void*) SkPathMeasureGlue::create },
{"native_setPath", "(JJZ)V", (void*) SkPathMeasureGlue::setPath },
{"native_getLength", "(J)F", (void*) SkPathMeasureGlue::getLength },
diff --git a/core/jni/android/graphics/PorterDuff.cpp b/core/jni/android/graphics/PorterDuff.cpp
index fed90a5d2f83..dfc3c9d7ed13 100644
--- a/core/jni/android/graphics/PorterDuff.cpp
+++ b/core/jni/android/graphics/PorterDuff.cpp
@@ -58,7 +58,7 @@ public:
};
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
{"nativeCreateXfermode","(I)J", (void*) SkPorterDuffGlue::CreateXfermode},
};
diff --git a/core/jni/android/graphics/Rasterizer.cpp b/core/jni/android/graphics/Rasterizer.cpp
index cfc23ac8ecb3..a106ecfeb65f 100644
--- a/core/jni/android/graphics/Rasterizer.cpp
+++ b/core/jni/android/graphics/Rasterizer.cpp
@@ -61,7 +61,7 @@ public:
}
};
-static JNINativeMethod gRasterizerMethods[] = {
+static const JNINativeMethod gRasterizerMethods[] = {
{"finalizer", "(J)V", (void*) SkRasterizerGlue::finalizer}
};
@@ -85,7 +85,7 @@ public:
}
};
-static JNINativeMethod gLayerRasterizerMethods[] = {
+static const JNINativeMethod gLayerRasterizerMethods[] = {
{ "nativeConstructor", "()J", (void*)SkLayerRasterizerGlue::create },
{ "nativeAddLayer", "(JJFF)V", (void*)SkLayerRasterizerGlue::addLayer }
};
diff --git a/core/jni/android/graphics/Region.cpp b/core/jni/android/graphics/Region.cpp
index e99bdfcc63fa..bcd0b60308bb 100644
--- a/core/jni/android/graphics/Region.cpp
+++ b/core/jni/android/graphics/Region.cpp
@@ -306,13 +306,13 @@ static jboolean RegionIter_next(JNIEnv* env, jobject, jlong pairHandle, jobject
////////////////////////////////////////////////////////////////////////////////////////////////////////////
-static JNINativeMethod gRegionIterMethods[] = {
+static const JNINativeMethod gRegionIterMethods[] = {
{ "nativeConstructor", "(J)J", (void*)RegionIter_constructor },
{ "nativeDestructor", "(J)V", (void*)RegionIter_destructor },
{ "nativeNext", "(JLandroid/graphics/Rect;)Z", (void*)RegionIter_next }
};
-static JNINativeMethod gRegionMethods[] = {
+static const JNINativeMethod gRegionMethods[] = {
// these are static methods
{ "nativeConstructor", "()J", (void*)Region_constructor },
{ "nativeDestructor", "(J)V", (void*)Region_destructor },
diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp
index 49c377e9c97f..799ed835197d 100644
--- a/core/jni/android/graphics/Shader.cpp
+++ b/core/jni/android/graphics/Shader.cpp
@@ -240,36 +240,36 @@ static jlong ComposeShader_create2(JNIEnv* env, jobject o,
///////////////////////////////////////////////////////////////////////////////////////////////
-static JNINativeMethod gColorMethods[] = {
+static const JNINativeMethod gColorMethods[] = {
{ "nativeRGBToHSV", "(III[F)V", (void*)Color_RGBToHSV },
{ "nativeHSVToColor", "(I[F)I", (void*)Color_HSVToColor }
};
-static JNINativeMethod gShaderMethods[] = {
+static const JNINativeMethod gShaderMethods[] = {
{ "nativeDestructor", "(J)V", (void*)Shader_destructor },
{ "nativeSetLocalMatrix", "(JJ)J", (void*)Shader_setLocalMatrix }
};
-static JNINativeMethod gBitmapShaderMethods[] = {
+static const JNINativeMethod gBitmapShaderMethods[] = {
{ "nativeCreate", "(Landroid/graphics/Bitmap;II)J", (void*)BitmapShader_constructor },
};
-static JNINativeMethod gLinearGradientMethods[] = {
+static const JNINativeMethod gLinearGradientMethods[] = {
{ "nativeCreate1", "(FFFF[I[FI)J", (void*)LinearGradient_create1 },
{ "nativeCreate2", "(FFFFIII)J", (void*)LinearGradient_create2 },
};
-static JNINativeMethod gRadialGradientMethods[] = {
+static const JNINativeMethod gRadialGradientMethods[] = {
{ "nativeCreate1", "(FFF[I[FI)J", (void*)RadialGradient_create1 },
{ "nativeCreate2", "(FFFIII)J", (void*)RadialGradient_create2 },
};
-static JNINativeMethod gSweepGradientMethods[] = {
+static const JNINativeMethod gSweepGradientMethods[] = {
{ "nativeCreate1", "(FF[I[F)J", (void*)SweepGradient_create1 },
{ "nativeCreate2", "(FFII)J", (void*)SweepGradient_create2 },
};
-static JNINativeMethod gComposeShaderMethods[] = {
+static const JNINativeMethod gComposeShaderMethods[] = {
{ "nativeCreate1", "(JJJ)J", (void*)ComposeShader_create1 },
{ "nativeCreate2", "(JJI)J", (void*)ComposeShader_create2 },
};
diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp
index b9e48a0c0cc8..61dc6e425ddf 100644
--- a/core/jni/android/graphics/SurfaceTexture.cpp
+++ b/core/jni/android/graphics/SurfaceTexture.cpp
@@ -241,17 +241,16 @@ static void SurfaceTexture_init(JNIEnv* env, jobject thiz, jboolean isDetached,
BufferQueue::createBufferQueue(&producer, &consumer);
if (singleBufferMode) {
- consumer->disableAsyncBuffer();
- consumer->setDefaultMaxBufferCount(1);
+ consumer->setMaxBufferCount(1);
}
sp<GLConsumer> surfaceTexture;
if (isDetached) {
surfaceTexture = new GLConsumer(consumer, GL_TEXTURE_EXTERNAL_OES,
- true, true);
+ true, !singleBufferMode);
} else {
surfaceTexture = new GLConsumer(consumer, texName,
- GL_TEXTURE_EXTERNAL_OES, true, true);
+ GL_TEXTURE_EXTERNAL_OES, true, !singleBufferMode);
}
if (surfaceTexture == 0) {
@@ -360,7 +359,7 @@ static jboolean SurfaceTexture_isReleased(JNIEnv* env, jobject thiz)
// ----------------------------------------------------------------------------
-static JNINativeMethod gSurfaceTextureMethods[] = {
+static const JNINativeMethod gSurfaceTextureMethods[] = {
{"nativeClassInit", "()V", (void*)SurfaceTexture_classInit },
{"nativeInit", "(ZIZLjava/lang/ref/WeakReference;)V", (void*)SurfaceTexture_init },
{"nativeFinalize", "()V", (void*)SurfaceTexture_finalize },
diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp
index e0cbc9efbd18..e97b768dd0cc 100644
--- a/core/jni/android/graphics/Typeface.cpp
+++ b/core/jni/android/graphics/Typeface.cpp
@@ -68,7 +68,7 @@ static void Typeface_setDefault(JNIEnv *env, jobject, jlong faceHandle) {
///////////////////////////////////////////////////////////////////////////////
-static JNINativeMethod gTypefaceMethods[] = {
+static const JNINativeMethod gTypefaceMethods[] = {
{ "nativeCreateFromTypeface", "(JI)J", (void*)Typeface_createFromTypeface },
{ "nativeCreateWeightAlias", "(JI)J", (void*)Typeface_createWeightAlias },
{ "nativeUnref", "(J)V", (void*)Typeface_unref },
diff --git a/core/jni/android/graphics/Xfermode.cpp b/core/jni/android/graphics/Xfermode.cpp
index 4a424aeb09a3..7441acc95cea 100644
--- a/core/jni/android/graphics/Xfermode.cpp
+++ b/core/jni/android/graphics/Xfermode.cpp
@@ -47,15 +47,15 @@ public:
///////////////////////////////////////////////////////////////////////////////
-static JNINativeMethod gXfermodeMethods[] = {
+static const JNINativeMethod gXfermodeMethods[] = {
{"finalizer", "(J)V", (void*) SkXfermodeGlue::finalizer}
};
-static JNINativeMethod gAvoidMethods[] = {
+static const JNINativeMethod gAvoidMethods[] = {
{"nativeCreate", "(III)J", (void*) SkXfermodeGlue::avoid_create}
};
-static JNINativeMethod gPixelXorMethods[] = {
+static const JNINativeMethod gPixelXorMethods[] = {
{"nativeCreate", "(I)J", (void*) SkXfermodeGlue::pixelxor_create}
};
diff --git a/core/jni/android/graphics/YuvToJpegEncoder.cpp b/core/jni/android/graphics/YuvToJpegEncoder.cpp
index 5eede2aee286..7d0c39cca018 100644
--- a/core/jni/android/graphics/YuvToJpegEncoder.cpp
+++ b/core/jni/android/graphics/YuvToJpegEncoder.cpp
@@ -243,7 +243,7 @@ static jboolean YuvImage_compressToJpeg(JNIEnv* env, jobject, jbyteArray inYuv,
}
///////////////////////////////////////////////////////////////////////////////
-static JNINativeMethod gYuvImageMethods[] = {
+static const JNINativeMethod gYuvImageMethods[] = {
{ "nativeCompressToJpeg", "([BIII[I[IILjava/io/OutputStream;[B)Z",
(void*)YuvImage_compressToJpeg }
};
diff --git a/core/jni/android/graphics/pdf/PdfDocument.cpp b/core/jni/android/graphics/pdf/PdfDocument.cpp
index a91b15b7fa41..7a13fe427b00 100644
--- a/core/jni/android/graphics/pdf/PdfDocument.cpp
+++ b/core/jni/android/graphics/pdf/PdfDocument.cpp
@@ -150,7 +150,7 @@ static void nativeClose(JNIEnv* env, jobject thiz, jlong documentPtr) {
document->close();
}
-static JNINativeMethod gPdfDocument_Methods[] = {
+static const JNINativeMethod gPdfDocument_Methods[] = {
{"nativeCreateDocument", "()J", (void*) nativeCreateDocument},
{"nativeStartPage", "(JIIIIII)J", (void*) nativeStartPage},
{"nativeFinishPage", "(J)V", (void*) nativeFinishPage},
diff --git a/core/jni/android/graphics/pdf/PdfEditor.cpp b/core/jni/android/graphics/pdf/PdfEditor.cpp
index 52b69e02e894..0177635f26b0 100644
--- a/core/jni/android/graphics/pdf/PdfEditor.cpp
+++ b/core/jni/android/graphics/pdf/PdfEditor.cpp
@@ -343,7 +343,7 @@ static void nativeSetPageCropBox(JNIEnv* env, jclass thiz, jlong documentPtr, ji
nativeSetPageBox(env, thiz, documentPtr, pageIndex, PAGE_BOX_CROP, mediaBox);
}
-static JNINativeMethod gPdfEditor_Methods[] = {
+static const JNINativeMethod gPdfEditor_Methods[] = {
{"nativeOpen", "(IJ)J", (void*) nativeOpen},
{"nativeClose", "(J)V", (void*) nativeClose},
{"nativeGetPageCount", "(J)I", (void*) nativeGetPageCount},
diff --git a/core/jni/android/graphics/pdf/PdfRenderer.cpp b/core/jni/android/graphics/pdf/PdfRenderer.cpp
index 006eef847a12..6ddfacf442e8 100644
--- a/core/jni/android/graphics/pdf/PdfRenderer.cpp
+++ b/core/jni/android/graphics/pdf/PdfRenderer.cpp
@@ -283,7 +283,7 @@ static void nativeRenderPage(JNIEnv* env, jclass thiz, jlong documentPtr, jlong
skBitmap.notifyPixelsChanged();
}
-static JNINativeMethod gPdfRenderer_Methods[] = {
+static const JNINativeMethod gPdfRenderer_Methods[] = {
{"nativeCreate", "(IJ)J", (void*) nativeCreate},
{"nativeClose", "(J)V", (void*) nativeClose},
{"nativeGetPageCount", "(J)I", (void*) nativeGetPageCount},
diff --git a/core/jni/android/opengl/util.cpp b/core/jni/android/opengl/util.cpp
index 40029bbe0aee..e045f5f36ada 100644
--- a/core/jni/android/opengl/util.cpp
+++ b/core/jni/android/opengl/util.cpp
@@ -1087,18 +1087,18 @@ static jint etc1_getHeight(JNIEnv *env, jclass clazz,
* JNI registration
*/
-static JNINativeMethod gMatrixMethods[] = {
+static const JNINativeMethod gMatrixMethods[] = {
{ "multiplyMM", "([FI[FI[FI)V", (void*)util_multiplyMM },
{ "multiplyMV", "([FI[FI[FI)V", (void*)util_multiplyMV },
};
-static JNINativeMethod gVisibilityMethods[] = {
+static const JNINativeMethod gVisibilityMethods[] = {
{ "computeBoundingSphere", "([FII[FI)V", (void*)util_computeBoundingSphere },
{ "frustumCullSpheres", "([FI[FII[III)I", (void*)util_frustumCullSpheres },
{ "visibilityTest", "([FI[FI[CII)I", (void*)util_visibilityTest },
};
-static JNINativeMethod gUtilsMethods[] = {
+static const JNINativeMethod gUtilsMethods[] = {
{ "native_getInternalFormat", "(Landroid/graphics/Bitmap;)I", (void*) util_getInternalFormat },
{ "native_getType", "(Landroid/graphics/Bitmap;)I", (void*) util_getType },
{ "native_texImage2D", "(IIILandroid/graphics/Bitmap;II)I", (void*)util_texImage2D },
@@ -1106,7 +1106,7 @@ static JNINativeMethod gUtilsMethods[] = {
{ "setTracingLevel", "(I)V", (void*)setTracingLevel },
};
-static JNINativeMethod gEtc1Methods[] = {
+static const JNINativeMethod gEtc1Methods[] = {
{ "encodeBlock", "(Ljava/nio/Buffer;ILjava/nio/Buffer;)V", (void*) etc1_encodeBlock },
{ "decodeBlock", "(Ljava/nio/Buffer;Ljava/nio/Buffer;)V", (void*) etc1_decodeBlock },
{ "getEncodedDataSize", "(II)I", (void*) etc1_getEncodedDataSize },
@@ -1120,11 +1120,11 @@ static JNINativeMethod gEtc1Methods[] = {
typedef struct _ClassRegistrationInfo {
const char* classPath;
- JNINativeMethod* methods;
+ const JNINativeMethod* methods;
size_t methodCount;
} ClassRegistrationInfo;
-static ClassRegistrationInfo gClasses[] = {
+static const ClassRegistrationInfo gClasses[] = {
{"android/opengl/Matrix", gMatrixMethods, NELEM(gMatrixMethods)},
{"android/opengl/Visibility", gVisibilityMethods, NELEM(gVisibilityMethods)},
{"android/opengl/GLUtils", gUtilsMethods, NELEM(gUtilsMethods)},
@@ -1136,7 +1136,7 @@ int register_android_opengl_classes(JNIEnv* env)
nativeClassInitBuffer(env);
int result = 0;
for (int i = 0; i < NELEM(gClasses); i++) {
- ClassRegistrationInfo* cri = &gClasses[i];
+ const ClassRegistrationInfo* cri = &gClasses[i];
result = RegisterMethodsOrDie(env, cri->classPath, cri->methods, cri->methodCount);
}
return result;
diff --git a/core/jni/android_animation_PropertyValuesHolder.cpp b/core/jni/android_animation_PropertyValuesHolder.cpp
index d11774189901..6065c2473978 100644
--- a/core/jni/android_animation_PropertyValuesHolder.cpp
+++ b/core/jni/android_animation_PropertyValuesHolder.cpp
@@ -139,7 +139,7 @@ static void android_animation_PropertyValuesHolder_callMultipleIntMethod(
env->ReleaseIntArrayElements(arg, intValues, JNI_ABORT);
}
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
{ "nGetIntMethod", "(Ljava/lang/Class;Ljava/lang/String;)J",
(void*)android_animation_PropertyValuesHolder_getIntMethod },
{ "nGetFloatMethod", "(Ljava/lang/Class;Ljava/lang/String;)J",
diff --git a/core/jni/android_content_res_ObbScanner.cpp b/core/jni/android_content_res_ObbScanner.cpp
index ef17db6b0fdf..36d78cf3aca0 100644
--- a/core/jni/android_content_res_ObbScanner.cpp
+++ b/core/jni/android_content_res_ObbScanner.cpp
@@ -76,7 +76,7 @@ static void android_content_res_ObbScanner_getObbInfo(JNIEnv* env, jobject clazz
/*
* JNI registration.
*/
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
{ "getObbInfo_native", "(Ljava/lang/String;Landroid/content/res/ObbInfo;)V",
(void*) android_content_res_ObbScanner_getObbInfo },
diff --git a/core/jni/android_database_CursorWindow.cpp b/core/jni/android_database_CursorWindow.cpp
index 580ac02789c5..bb09d001037d 100644
--- a/core/jni/android_database_CursorWindow.cpp
+++ b/core/jni/android_database_CursorWindow.cpp
@@ -477,7 +477,7 @@ static jboolean nativePutNull(JNIEnv* env, jclass clazz, jlong windowPtr,
return true;
}
-static JNINativeMethod sMethods[] =
+static const JNINativeMethod sMethods[] =
{
/* name, signature, funcPtr */
{ "nativeCreate", "(Ljava/lang/String;I)J",
diff --git a/core/jni/android_database_SQLiteConnection.cpp b/core/jni/android_database_SQLiteConnection.cpp
index 7a3cdf68fb18..bcc3bb09b69d 100644
--- a/core/jni/android_database_SQLiteConnection.cpp
+++ b/core/jni/android_database_SQLiteConnection.cpp
@@ -786,7 +786,7 @@ static void nativeResetCancel(JNIEnv* env, jobject clazz, jlong connectionPtr,
}
-static JNINativeMethod sMethods[] =
+static const JNINativeMethod sMethods[] =
{
/* name, signature, funcPtr */
{ "nativeOpen", "(Ljava/lang/String;ILjava/lang/String;ZZ)J",
diff --git a/core/jni/android_database_SQLiteDebug.cpp b/core/jni/android_database_SQLiteDebug.cpp
index 26e13cf10e71..4e4c36cbb7e1 100644
--- a/core/jni/android_database_SQLiteDebug.cpp
+++ b/core/jni/android_database_SQLiteDebug.cpp
@@ -58,7 +58,7 @@ static void nativeGetPagerStats(JNIEnv *env, jobject clazz, jobject statsObj)
* JNI registration.
*/
-static JNINativeMethod gMethods[] =
+static const JNINativeMethod gMethods[] =
{
{ "nativeGetPagerStats", "(Landroid/database/sqlite/SQLiteDebug$PagerStats;)V",
(void*) nativeGetPagerStats },
diff --git a/core/jni/android_database_SQLiteGlobal.cpp b/core/jni/android_database_SQLiteGlobal.cpp
index 0a1c9f75edec..03e2387f24bc 100644
--- a/core/jni/android_database_SQLiteGlobal.cpp
+++ b/core/jni/android_database_SQLiteGlobal.cpp
@@ -75,7 +75,7 @@ static jint nativeReleaseMemory(JNIEnv* env, jclass clazz) {
return sqlite3_release_memory(SOFT_HEAP_LIMIT);
}
-static JNINativeMethod sMethods[] =
+static const JNINativeMethod sMethods[] =
{
/* name, signature, funcPtr */
{ "nativeReleaseMemory", "()I", (void*)nativeReleaseMemory },
diff --git a/core/jni/android_ddm_DdmHandleNativeHeap.cpp b/core/jni/android_ddm_DdmHandleNativeHeap.cpp
index ae96936ecba5..3e7a04efc536 100644
--- a/core/jni/android_ddm_DdmHandleNativeHeap.cpp
+++ b/core/jni/android_ddm_DdmHandleNativeHeap.cpp
@@ -105,7 +105,7 @@ static jbyteArray DdmHandleNativeHeap_getLeakInfo(JNIEnv* env, jobject) {
return array;
}
-static JNINativeMethod method_table[] = {
+static const JNINativeMethod method_table[] = {
{ "getLeakInfo", "()[B", (void*) DdmHandleNativeHeap_getLeakInfo },
};
diff --git a/core/jni/android_graphics_Canvas.cpp b/core/jni/android_graphics_Canvas.cpp
index 5ddf2350d278..32a877ae3398 100644
--- a/core/jni/android_graphics_Canvas.cpp
+++ b/core/jni/android_graphics_Canvas.cpp
@@ -746,7 +746,7 @@ static void freeTextLayoutCaches(JNIEnv* env, jobject) {
}; // namespace CanvasJNI
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
{"finalizer", "(J)V", (void*) CanvasJNI::finalizer},
{"initRaster", "(Landroid/graphics/Bitmap;)J", (void*) CanvasJNI::initRaster},
{"native_setBitmap", "(JLandroid/graphics/Bitmap;)V", (void*) CanvasJNI::setBitmap},
diff --git a/core/jni/android_graphics_Picture.cpp b/core/jni/android_graphics_Picture.cpp
index fd42ddb9226e..03fcdef8fbfe 100644
--- a/core/jni/android_graphics_Picture.cpp
+++ b/core/jni/android_graphics_Picture.cpp
@@ -91,7 +91,7 @@ static void android_graphics_Picture_endRecording(JNIEnv* env, jobject, jlong pi
pict->endRecording();
}
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
{"nativeGetWidth", "(J)I", (void*) android_graphics_Picture_getWidth},
{"nativeGetHeight", "(J)I", (void*) android_graphics_Picture_getHeight},
{"nativeConstructor", "(J)J", (void*) android_graphics_Picture_newPicture},
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index 4f44c262f261..414eba79f22d 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -949,7 +949,7 @@ static void android_hardware_Camera_enableFocusMoveCallback(JNIEnv *env, jobject
//-------------------------------------------------
-static JNINativeMethod camMethods[] = {
+static const JNINativeMethod camMethods[] = {
{ "getNumberOfCameras",
"()I",
(void *)android_hardware_Camera_getNumberOfCameras },
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index 7d0afdcdd109..2e5cda069538 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -343,7 +343,7 @@ static jint nativeInjectSensorData(JNIEnv *env, jclass clazz, jlong eventQ, jint
}
//----------------------------------------------------------------------------
-static JNINativeMethod gSystemSensorManagerMethods[] = {
+static const JNINativeMethod gSystemSensorManagerMethods[] = {
{"nativeClassInit",
"()V",
(void*)nativeClassInit },
@@ -360,7 +360,7 @@ static JNINativeMethod gSystemSensorManagerMethods[] = {
(void*)nativeIsDataInjectionEnabled},
};
-static JNINativeMethod gBaseEventQueueMethods[] = {
+static const JNINativeMethod gBaseEventQueueMethods[] = {
{"nativeInitBaseEventQueue",
"(JLjava/lang/ref/WeakReference;Landroid/os/MessageQueue;[FLjava/lang/String;ILjava/lang/String;)J",
(void*)nativeInitSensorEventQueue },
diff --git a/core/jni/android_hardware_SerialPort.cpp b/core/jni/android_hardware_SerialPort.cpp
index 2d2ff4d97cb9..393dc7b9f4fd 100644
--- a/core/jni/android_hardware_SerialPort.cpp
+++ b/core/jni/android_hardware_SerialPort.cpp
@@ -243,7 +243,7 @@ android_hardware_SerialPort_send_break(JNIEnv *env, jobject thiz)
tcsendbreak(fd, 0);
}
-static JNINativeMethod method_table[] = {
+static const JNINativeMethod method_table[] = {
{"native_open", "(Ljava/io/FileDescriptor;I)V",
(void *)android_hardware_SerialPort_open},
{"native_close", "()V", (void *)android_hardware_SerialPort_close},
diff --git a/core/jni/android_hardware_SoundTrigger.cpp b/core/jni/android_hardware_SoundTrigger.cpp
index 1c4c9ecc8a09..048b3c71c2c3 100644
--- a/core/jni/android_hardware_SoundTrigger.cpp
+++ b/core/jni/android_hardware_SoundTrigger.cpp
@@ -768,14 +768,14 @@ android_hardware_SoundTrigger_stopRecognition(JNIEnv *env, jobject thiz,
return status;
}
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
{"listModules",
"(Ljava/util/ArrayList;)I",
(void *)android_hardware_SoundTrigger_listModules},
};
-static JNINativeMethod gModuleMethods[] = {
+static const JNINativeMethod gModuleMethods[] = {
{"native_setup",
"(Ljava/lang/Object;)V",
(void *)android_hardware_SoundTrigger_setup},
diff --git a/core/jni/android_hardware_UsbDevice.cpp b/core/jni/android_hardware_UsbDevice.cpp
index ef3b6463cd97..89d33e2ace1c 100644
--- a/core/jni/android_hardware_UsbDevice.cpp
+++ b/core/jni/android_hardware_UsbDevice.cpp
@@ -44,7 +44,7 @@ android_hardware_UsbDevice_get_device_name(JNIEnv *env, jobject clazz, jint id)
return result;
}
-static JNINativeMethod method_table[] = {
+static const JNINativeMethod method_table[] = {
// static methods
{ "native_get_device_id", "(Ljava/lang/String;)I",
(void*)android_hardware_UsbDevice_get_device_id },
diff --git a/core/jni/android_hardware_UsbDeviceConnection.cpp b/core/jni/android_hardware_UsbDeviceConnection.cpp
index e0cae6f3136f..1ba9fc58800c 100644
--- a/core/jni/android_hardware_UsbDeviceConnection.cpp
+++ b/core/jni/android_hardware_UsbDeviceConnection.cpp
@@ -246,7 +246,7 @@ android_hardware_UsbDeviceConnection_get_serial(JNIEnv *env, jobject thiz)
return result;
}
-static JNINativeMethod method_table[] = {
+static const JNINativeMethod method_table[] = {
{"native_open", "(Ljava/lang/String;Ljava/io/FileDescriptor;)Z",
(void *)android_hardware_UsbDeviceConnection_open},
{"native_close", "()V", (void *)android_hardware_UsbDeviceConnection_close},
diff --git a/core/jni/android_hardware_UsbRequest.cpp b/core/jni/android_hardware_UsbRequest.cpp
index ce99e15bffc0..399e7b16f073 100644
--- a/core/jni/android_hardware_UsbRequest.cpp
+++ b/core/jni/android_hardware_UsbRequest.cpp
@@ -190,7 +190,7 @@ android_hardware_UsbRequest_cancel(JNIEnv *env, jobject thiz)
return (usb_request_cancel(request) == 0);
}
-static JNINativeMethod method_table[] = {
+static const JNINativeMethod method_table[] = {
{"native_init", "(Landroid/hardware/usb/UsbDeviceConnection;IIII)Z",
(void *)android_hardware_UsbRequest_init},
{"native_close", "()V", (void *)android_hardware_UsbRequest_close},
diff --git a/core/jni/android_hardware_camera2_CameraMetadata.cpp b/core/jni/android_hardware_camera2_CameraMetadata.cpp
index fb2268911be3..793002734111 100644
--- a/core/jni/android_hardware_camera2_CameraMetadata.cpp
+++ b/core/jni/android_hardware_camera2_CameraMetadata.cpp
@@ -529,7 +529,7 @@ static void CameraMetadata_writeToParcel(JNIEnv *env, jobject thiz, jobject parc
//-------------------------------------------------
-static JNINativeMethod gCameraMetadataMethods[] = {
+static const JNINativeMethod gCameraMetadataMethods[] = {
// static methods
{ "nativeClassInit",
"()V",
diff --git a/core/jni/android_hardware_camera2_DngCreator.cpp b/core/jni/android_hardware_camera2_DngCreator.cpp
index 8b69bbd084b5..738a62ad5772 100644
--- a/core/jni/android_hardware_camera2_DngCreator.cpp
+++ b/core/jni/android_hardware_camera2_DngCreator.cpp
@@ -2280,7 +2280,7 @@ static void DngCreator_nativeWriteInputStream(JNIEnv* env, jobject thiz, jobject
} /*extern "C" */
-static JNINativeMethod gDngCreatorMethods[] = {
+static const JNINativeMethod gDngCreatorMethods[] = {
{"nativeClassInit", "()V", (void*) DngCreator_nativeClassInit},
{"nativeInit", "(Landroid/hardware/camera2/impl/CameraMetadataNative;"
"Landroid/hardware/camera2/impl/CameraMetadataNative;Ljava/lang/String;)V",
diff --git a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
index 63915ed1c134..f1ea7ec7e8a2 100644
--- a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
+++ b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
@@ -730,7 +730,7 @@ static jint LegacyCameraDevice_nativeGetJpegFooterSize(JNIEnv* env, jobject thiz
} // extern "C"
-static JNINativeMethod gCameraDeviceMethods[] = {
+static const JNINativeMethod gCameraDeviceMethods[] = {
{ "nativeDetectSurfaceType",
"(Landroid/view/Surface;)I",
(void *)LegacyCameraDevice_nativeDetectSurfaceType },
diff --git a/core/jni/android_hardware_camera2_legacy_PerfMeasurement.cpp b/core/jni/android_hardware_camera2_legacy_PerfMeasurement.cpp
index 7257597ca6cf..f0420585bfa4 100644
--- a/core/jni/android_hardware_camera2_legacy_PerfMeasurement.cpp
+++ b/core/jni/android_hardware_camera2_legacy_PerfMeasurement.cpp
@@ -302,7 +302,7 @@ static jlong PerfMeasurement_nativeGetNextGlDuration(JNIEnv* env,
} // extern "C"
-static JNINativeMethod gPerfMeasurementMethods[] = {
+static const JNINativeMethod gPerfMeasurementMethods[] = {
{ "nativeCreateContext",
"(I)J",
(jlong *)PerfMeasurement_nativeCreateContext },
diff --git a/core/jni/android_hardware_location_ActivityRecognitionHardware.cpp b/core/jni/android_hardware_location_ActivityRecognitionHardware.cpp
index 470c5ba8e2a3..4b279f63c99f 100644
--- a/core/jni/android_hardware_location_ActivityRecognitionHardware.cpp
+++ b/core/jni/android_hardware_location_ActivityRecognitionHardware.cpp
@@ -275,7 +275,7 @@ static int flush(JNIEnv* env, jobject obj) {
}
-static JNINativeMethod sMethods[] = {
+static const JNINativeMethod sMethods[] = {
// {"name", "signature", (void*) functionPointer },
{ "nativeClassInit", "()V", (void*) class_init },
{ "nativeInitialize", "()V", (void*) initialize },
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index 6c2bbd45ea51..b977e377f2f3 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -682,7 +682,7 @@ static void android_media_AudioRecord_disableDeviceCallback(
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
// name, signature, funcPtr
{"native_start", "(II)I", (void *)android_media_AudioRecord_start},
{"native_stop", "()V", (void *)android_media_AudioRecord_stop},
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 91b3278c2e2b..6d3c7d7363c6 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -1616,7 +1616,7 @@ android_media_AudioSystem_systemReady(JNIEnv *env, jobject thiz)
// ----------------------------------------------------------------------------
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
{"setParameters", "(Ljava/lang/String;)I", (void *)android_media_AudioSystem_setParameters},
{"getParameters", "(Ljava/lang/String;)Ljava/lang/String;", (void *)android_media_AudioSystem_getParameters},
{"muteMicrophone", "(Z)I", (void *)android_media_AudioSystem_muteMicrophone},
@@ -1663,7 +1663,7 @@ static JNINativeMethod gMethods[] = {
};
-static JNINativeMethod gEventHandlerMethods[] = {
+static const JNINativeMethod gEventHandlerMethods[] = {
{"native_setup",
"(Ljava/lang/Object;)V",
(void *)android_media_AudioSystem_eventHandlerSetup},
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 5faa15008359..7860b74cc804 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -1052,7 +1052,7 @@ static void android_media_AudioTrack_disableDeviceCallback(
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
// name, signature, funcPtr
{"native_start", "()V", (void *)android_media_AudioTrack_start},
{"native_stop", "()V", (void *)android_media_AudioTrack_stop},
diff --git a/core/jni/android_media_JetPlayer.cpp b/core/jni/android_media_JetPlayer.cpp
index d441f1015dfc..873c3f2e07e1 100644
--- a/core/jni/android_media_JetPlayer.cpp
+++ b/core/jni/android_media_JetPlayer.cpp
@@ -488,7 +488,7 @@ android_media_JetPlayer_clearQueue(JNIEnv *env, jobject thiz)
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
// name, signature, funcPtr
{"native_setup", "(Ljava/lang/Object;II)Z", (void *)android_media_JetPlayer_setup},
{"native_finalize", "()V", (void *)android_media_JetPlayer_finalize},
diff --git a/core/jni/android_media_RemoteDisplay.cpp b/core/jni/android_media_RemoteDisplay.cpp
index 9bc223b57a42..bd1a6ecaf95c 100644
--- a/core/jni/android_media_RemoteDisplay.cpp
+++ b/core/jni/android_media_RemoteDisplay.cpp
@@ -177,7 +177,7 @@ static void nativeDispose(JNIEnv* env, jobject remoteDisplayObj, jlong ptr) {
// ----------------------------------------------------------------------------
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
{"nativeListen", "(Ljava/lang/String;Ljava/lang/String;)J",
(void*)nativeListen },
{"nativeDispose", "(J)V",
diff --git a/core/jni/android_media_ToneGenerator.cpp b/core/jni/android_media_ToneGenerator.cpp
index 243f0400775e..aec62631c559 100644
--- a/core/jni/android_media_ToneGenerator.cpp
+++ b/core/jni/android_media_ToneGenerator.cpp
@@ -123,7 +123,7 @@ static void android_media_ToneGenerator_native_finalize(JNIEnv *env,
// ----------------------------------------------------------------------------
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
{ "startTone", "(II)Z", (void *)android_media_ToneGenerator_startTone },
{ "stopTone", "()V", (void *)android_media_ToneGenerator_stopTone },
{ "getAudioSessionId", "()I", (void *)android_media_ToneGenerator_getAudioSessionId},
diff --git a/core/jni/android_net_LocalSocketImpl.cpp b/core/jni/android_net_LocalSocketImpl.cpp
index c137b17426e0..d6d431019a6d 100644
--- a/core/jni/android_net_LocalSocketImpl.cpp
+++ b/core/jni/android_net_LocalSocketImpl.cpp
@@ -495,7 +495,7 @@ static jobject socket_get_peer_credentials(JNIEnv *env,
/*
* JNI registration.
*/
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
{"connectLocal", "(Ljava/io/FileDescriptor;Ljava/lang/String;I)V",
(void*)socket_connect_local},
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index fada7ac21b1d..ba0876d74b17 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -302,7 +302,7 @@ static jboolean android_net_utils_queryUserAccess(JNIEnv *env, jobject thiz, jin
/*
* JNI registration.
*/
-static JNINativeMethod gNetworkUtilMethods[] = {
+static const JNINativeMethod gNetworkUtilMethods[] = {
/* name, signature, funcPtr */
{ "resetConnections", "(Ljava/lang/String;I)I", (void *)android_net_utils_resetConnections },
{ "startDhcp", "(Ljava/lang/String;)Z", (void *)android_net_utils_startDhcp },
diff --git a/core/jni/android_net_TrafficStats.cpp b/core/jni/android_net_TrafficStats.cpp
index 735441743516..7b7d0cf498c3 100644
--- a/core/jni/android_net_TrafficStats.cpp
+++ b/core/jni/android_net_TrafficStats.cpp
@@ -185,7 +185,7 @@ static jlong getUidStat(JNIEnv* env, jclass clazz, jint uid, jint type) {
}
}
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
{"nativeGetTotalStat", "(I)J", (void*) getTotalStat},
{"nativeGetIfaceStat", "(Ljava/lang/String;I)J", (void*) getIfaceStat},
{"nativeGetUidStat", "(II)J", (void*) getUidStat},
diff --git a/core/jni/android_opengl_EGL14.cpp b/core/jni/android_opengl_EGL14.cpp
index 9f5b3bc3f5b2..568473c14dc5 100644
--- a/core/jni/android_opengl_EGL14.cpp
+++ b/core/jni/android_opengl_EGL14.cpp
@@ -1231,7 +1231,7 @@ android_eglCopyBuffers
static const char *classPathName = "android/opengl/EGL14";
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
{"_nativeClassInit", "()V", (void*)nativeClassInit },
{"eglGetError", "()I", (void *) android_eglGetError },
{"eglGetDisplay", "(I)Landroid/opengl/EGLDisplay;", (void *) android_eglGetDisplayInt },
diff --git a/core/jni/android_opengl_EGLExt.cpp b/core/jni/android_opengl_EGLExt.cpp
index 60a3bf642915..62ccad4d85f0 100644
--- a/core/jni/android_opengl_EGLExt.cpp
+++ b/core/jni/android_opengl_EGLExt.cpp
@@ -149,7 +149,7 @@ android_eglPresentationTimeANDROID
static const char *classPathName = "android/opengl/EGLExt";
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
{"_nativeClassInit", "()V", (void*)nativeClassInit },
{"eglPresentationTimeANDROID", "(Landroid/opengl/EGLDisplay;Landroid/opengl/EGLSurface;J)Z", (void *) android_eglPresentationTimeANDROID },
};
diff --git a/core/jni/android_opengl_GLES10.cpp b/core/jni/android_opengl_GLES10.cpp
index dac98defbc79..f4135c213e36 100644
--- a/core/jni/android_opengl_GLES10.cpp
+++ b/core/jni/android_opengl_GLES10.cpp
@@ -3184,7 +3184,7 @@ android_glViewport__IIII
static const char *classPathName = "android/opengl/GLES10";
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
{"_nativeClassInit", "()V", (void*)nativeClassInit },
{"glActiveTexture", "(I)V", (void *) android_glActiveTexture__I },
{"glAlphaFunc", "(IF)V", (void *) android_glAlphaFunc__IF },
diff --git a/core/jni/android_opengl_GLES10Ext.cpp b/core/jni/android_opengl_GLES10Ext.cpp
index 95be11bde598..4dc42339b6e5 100644
--- a/core/jni/android_opengl_GLES10Ext.cpp
+++ b/core/jni/android_opengl_GLES10Ext.cpp
@@ -582,7 +582,7 @@ exit:
static const char *classPathName = "android/opengl/GLES10Ext";
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
{"_nativeClassInit", "()V", (void*)nativeClassInit },
{"glQueryMatrixxOES", "([II[II)I", (void *) android_glQueryMatrixxOES___3II_3II },
{"glQueryMatrixxOES", "(Ljava/nio/IntBuffer;Ljava/nio/IntBuffer;)I", (void *) android_glQueryMatrixxOES__Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2 },
diff --git a/core/jni/android_opengl_GLES11.cpp b/core/jni/android_opengl_GLES11.cpp
index 6970a3c7e180..2625e03c962e 100644
--- a/core/jni/android_opengl_GLES11.cpp
+++ b/core/jni/android_opengl_GLES11.cpp
@@ -3065,7 +3065,7 @@ android_glVertexPointer__IIII
static const char *classPathName = "android/opengl/GLES11";
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
{"_nativeClassInit", "()V", (void*)nativeClassInit },
{"glBindBuffer", "(II)V", (void *) android_glBindBuffer__II },
{"glBufferData", "(IILjava/nio/Buffer;I)V", (void *) android_glBufferData__IILjava_nio_Buffer_2I },
diff --git a/core/jni/android_opengl_GLES11Ext.cpp b/core/jni/android_opengl_GLES11Ext.cpp
index 6422ff28e190..fb85cb0f8d95 100644
--- a/core/jni/android_opengl_GLES11Ext.cpp
+++ b/core/jni/android_opengl_GLES11Ext.cpp
@@ -3573,7 +3573,7 @@ android_glGetTexGenxvOES__IILjava_nio_IntBuffer_2
static const char *classPathName = "android/opengl/GLES11Ext";
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
{"_nativeClassInit", "()V", (void*)nativeClassInit },
{"glBlendEquationSeparateOES", "(II)V", (void *) android_glBlendEquationSeparateOES__II },
{"glBlendFuncSeparateOES", "(IIII)V", (void *) android_glBlendFuncSeparateOES__IIII },
diff --git a/core/jni/android_opengl_GLES20.cpp b/core/jni/android_opengl_GLES20.cpp
index f9a0dfeb444c..b9f61a91ec90 100644
--- a/core/jni/android_opengl_GLES20.cpp
+++ b/core/jni/android_opengl_GLES20.cpp
@@ -6152,7 +6152,7 @@ android_glViewport__IIII
static const char *classPathName = "android/opengl/GLES20";
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
{"_nativeClassInit", "()V", (void*)nativeClassInit },
{"glActiveTexture", "(I)V", (void *) android_glActiveTexture__I },
{"glAttachShader", "(II)V", (void *) android_glAttachShader__II },
diff --git a/core/jni/android_opengl_GLES30.cpp b/core/jni/android_opengl_GLES30.cpp
index 1d92cd46527a..8eb50444762c 100644
--- a/core/jni/android_opengl_GLES30.cpp
+++ b/core/jni/android_opengl_GLES30.cpp
@@ -5167,7 +5167,7 @@ android_glGetInternalformativ__IIIILjava_nio_IntBuffer_2
static const char *classPathName = "android/opengl/GLES30";
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
{"_nativeClassInit", "()V", (void*)nativeClassInit },
{"glReadBuffer", "(I)V", (void *) android_glReadBuffer__I },
{"glDrawRangeElements", "(IIIIILjava/nio/Buffer;)V", (void *) android_glDrawRangeElements__IIIIILjava_nio_Buffer_2 },
diff --git a/core/jni/android_opengl_GLES31.cpp b/core/jni/android_opengl_GLES31.cpp
index 92ecbe0b99df..e427388a10e9 100644
--- a/core/jni/android_opengl_GLES31.cpp
+++ b/core/jni/android_opengl_GLES31.cpp
@@ -3175,7 +3175,7 @@ android_glVertexBindingDivisor__II
static const char *classPathName = "android/opengl/GLES31";
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
{"_nativeClassInit", "()V", (void*)nativeClassInit },
{"glDispatchCompute", "(III)V", (void *) android_glDispatchCompute__III },
{"glDispatchComputeIndirect", "(J)V", (void *) android_glDispatchComputeIndirect },
diff --git a/core/jni/android_opengl_GLES31Ext.cpp b/core/jni/android_opengl_GLES31Ext.cpp
index 28563089e85a..180c69348853 100644
--- a/core/jni/android_opengl_GLES31Ext.cpp
+++ b/core/jni/android_opengl_GLES31Ext.cpp
@@ -1443,7 +1443,7 @@ android_glTexBufferRangeEXT__IIIII
static const char *classPathName = "android/opengl/GLES31Ext";
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
{"_nativeClassInit", "()V", (void*)nativeClassInit },
{"glBlendBarrierKHR", "()V", (void *) android_glBlendBarrierKHR__ },
{"glDebugMessageControlKHR", "(IIII[IIZ)V", (void *) android_glDebugMessageControlKHR__IIII_3IIZ },
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index b969477bf258..097bbac84e3f 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -973,7 +973,7 @@ static void android_os_Debug_dumpNativeBacktraceToFile(JNIEnv* env, jobject claz
* JNI registration.
*/
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
{ "getNativeHeapSize", "()J",
(void*) android_os_Debug_getNativeHeapSize },
{ "getNativeHeapAllocatedSize", "()J",
diff --git a/core/jni/android_os_MessageQueue.cpp b/core/jni/android_os_MessageQueue.cpp
index d2db3c9ab5b3..e57a7190cfce 100644
--- a/core/jni/android_os_MessageQueue.cpp
+++ b/core/jni/android_os_MessageQueue.cpp
@@ -209,7 +209,7 @@ static void android_os_MessageQueue_nativeSetFileDescriptorEvents(JNIEnv* env, j
// ----------------------------------------------------------------------------
-static JNINativeMethod gMessageQueueMethods[] = {
+static const JNINativeMethod gMessageQueueMethods[] = {
/* name, signature, funcPtr */
{ "nativeInit", "()J", (void*)android_os_MessageQueue_nativeInit },
{ "nativeDestroy", "(J)V", (void*)android_os_MessageQueue_nativeDestroy },
diff --git a/core/jni/android_os_SELinux.cpp b/core/jni/android_os_SELinux.cpp
index 762b88f5dbee..8ba77aed1d04 100644
--- a/core/jni/android_os_SELinux.cpp
+++ b/core/jni/android_os_SELinux.cpp
@@ -320,7 +320,7 @@ static jboolean native_restorecon(JNIEnv *env, jobject, jstring pathnameStr, jin
/*
* JNI registration.
*/
-static JNINativeMethod method_table[] = {
+static const JNINativeMethod method_table[] = {
/* name, signature, funcPtr */
{ "checkSELinuxAccess" , "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z" , (void*)checkSELinuxAccess },
{ "getContext" , "()Ljava/lang/String;" , (void*)getCon },
diff --git a/core/jni/android_os_SystemClock.cpp b/core/jni/android_os_SystemClock.cpp
index dfe024e8a473..d98407deb7e7 100644
--- a/core/jni/android_os_SystemClock.cpp
+++ b/core/jni/android_os_SystemClock.cpp
@@ -104,7 +104,7 @@ static jlong android_os_SystemClock_elapsedRealtimeNano(JNIEnv* env,
/*
* JNI registration.
*/
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
{ "uptimeMillis", "()J",
(void*) android_os_SystemClock_uptimeMillis },
diff --git a/core/jni/android_os_SystemProperties.cpp b/core/jni/android_os_SystemProperties.cpp
index 554d304290cf..5dace6b7e536 100644
--- a/core/jni/android_os_SystemProperties.cpp
+++ b/core/jni/android_os_SystemProperties.cpp
@@ -220,7 +220,7 @@ static void SystemProperties_add_change_callback(JNIEnv *env, jobject clazz)
}
}
-static JNINativeMethod method_table[] = {
+static const JNINativeMethod method_table[] = {
{ "native_get", "(Ljava/lang/String;)Ljava/lang/String;",
(void*) SystemProperties_getS },
{ "native_get", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
diff --git a/core/jni/android_os_Trace.cpp b/core/jni/android_os_Trace.cpp
index 3fd3b3c9ae15..30fc47bba751 100644
--- a/core/jni/android_os_Trace.cpp
+++ b/core/jni/android_os_Trace.cpp
@@ -105,7 +105,7 @@ static void android_os_Trace_nativeSetTracingEnabled(JNIEnv* env,
atrace_set_tracing_enabled(enabled);
}
-static JNINativeMethod gTraceMethods[] = {
+static const JNINativeMethod gTraceMethods[] = {
/* name, signature, funcPtr */
{ "nativeGetEnabledTags",
"()J",
diff --git a/core/jni/android_os_UEventObserver.cpp b/core/jni/android_os_UEventObserver.cpp
index eb36f8549cfa..30d40a2a08ad 100644
--- a/core/jni/android_os_UEventObserver.cpp
+++ b/core/jni/android_os_UEventObserver.cpp
@@ -103,7 +103,7 @@ static void nativeRemoveMatch(JNIEnv* env, jclass clazz, jstring matchStr) {
}
}
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
{ "nativeSetup", "()V",
(void *)nativeSetup },
{ "nativeWaitForNextEvent", "()Ljava/lang/String;",
diff --git a/core/jni/android_server_NetworkManagementSocketTagger.cpp b/core/jni/android_server_NetworkManagementSocketTagger.cpp
index ca21fd716a5f..818bf53d97a4 100644
--- a/core/jni/android_server_NetworkManagementSocketTagger.cpp
+++ b/core/jni/android_server_NetworkManagementSocketTagger.cpp
@@ -83,7 +83,7 @@ static jint QTagUid_deleteTagData(JNIEnv* env, jclass,
return (jint)res;
}
-static JNINativeMethod gQTagUidMethods[] = {
+static const JNINativeMethod gQTagUidMethods[] = {
{ "native_tagSocketFd", "(Ljava/io/FileDescriptor;II)I", (void*)QTagUid_tagSocketFd},
{ "native_untagSocketFd", "(Ljava/io/FileDescriptor;)I", (void*)QTagUid_untagSocketFd},
{ "native_setCounterSet", "(II)I", (void*)QTagUid_setCounterSet},
diff --git a/core/jni/android_text_AndroidBidi.cpp b/core/jni/android_text_AndroidBidi.cpp
index 328542954efa..2a3f0361a9cd 100644
--- a/core/jni/android_text_AndroidBidi.cpp
+++ b/core/jni/android_text_AndroidBidi.cpp
@@ -56,7 +56,7 @@ static jint runBidi(JNIEnv* env, jobject obj, jint dir, jcharArray chsArray,
return result;
}
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
{ "runBidi", "(I[C[BIZ)I", (void*) runBidi }
};
diff --git a/core/jni/android_text_AndroidCharacter.cpp b/core/jni/android_text_AndroidCharacter.cpp
index 9258248083d0..474a74e8776c 100644
--- a/core/jni/android_text_AndroidCharacter.cpp
+++ b/core/jni/android_text_AndroidCharacter.cpp
@@ -178,7 +178,7 @@ static jchar getMirror(JNIEnv* env, jobject obj, jchar c)
return u_charMirror(c);
}
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
{ "getDirectionalities", "([C[BI)V",
(void*) getDirectionalities },
{ "getEastAsianWidth", "(C)I",
diff --git a/core/jni/android_text_StaticLayout.cpp b/core/jni/android_text_StaticLayout.cpp
index 90e4bb64133e..a151e004922d 100644
--- a/core/jni/android_text_StaticLayout.cpp
+++ b/core/jni/android_text_StaticLayout.cpp
@@ -172,7 +172,7 @@ static void nGetWidths(JNIEnv* env, jclass, jlong nativePtr, jfloatArray widths)
env->SetFloatArrayRegion(widths, 0, b->size(), b->charWidths());
}
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
// TODO performance: many of these are candidates for fast jni, awaiting guidance
{"nNewBuilder", "()J", (void*) nNewBuilder},
{"nFreeBuilder", "(J)V", (void*) nFreeBuilder},
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 7ca0654f9656..614e82f803ff 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -2112,7 +2112,7 @@ static jint android_content_AssetManager_getGlobalAssetManagerCount(JNIEnv* env,
/*
* JNI registration.
*/
-static JNINativeMethod gAssetManagerMethods[] = {
+static const JNINativeMethod gAssetManagerMethods[] = {
/* name, signature, funcPtr */
// Basic asset stuff.
diff --git a/core/jni/android_util_EventLog.cpp b/core/jni/android_util_EventLog.cpp
index 05bc12563b6c..4f8a2cb91506 100644
--- a/core/jni/android_util_EventLog.cpp
+++ b/core/jni/android_util_EventLog.cpp
@@ -249,7 +249,7 @@ static void android_util_EventLog_readEvents(JNIEnv* env, jobject clazz UNUSED,
/*
* JNI registration.
*/
-static JNINativeMethod gRegisterMethods[] = {
+static const JNINativeMethod gRegisterMethods[] = {
/* name, signature, funcPtr */
{ "writeEvent", "(II)I", (void*) android_util_EventLog_writeEvent_Integer },
{ "writeEvent", "(IJ)I", (void*) android_util_EventLog_writeEvent_Long },
diff --git a/core/jni/android_util_FileObserver.cpp b/core/jni/android_util_FileObserver.cpp
index 067d298580bc..2b93b6d61905 100644
--- a/core/jni/android_util_FileObserver.cpp
+++ b/core/jni/android_util_FileObserver.cpp
@@ -127,7 +127,7 @@ static void android_os_fileobserver_stopWatching(JNIEnv* env, jobject object, ji
#endif
}
-static JNINativeMethod sMethods[] = {
+static const JNINativeMethod sMethods[] = {
/* name, signature, funcPtr */
{ "init", "()I", (void*)android_os_fileobserver_init },
{ "observe", "(I)V", (void*)android_os_fileobserver_observe },
diff --git a/core/jni/android_util_Log.cpp b/core/jni/android_util_Log.cpp
index 2b1067bede5d..2d23cda5ff15 100644
--- a/core/jni/android_util_Log.cpp
+++ b/core/jni/android_util_Log.cpp
@@ -111,7 +111,7 @@ static jint android_util_Log_println_native(JNIEnv* env, jobject clazz,
/*
* JNI registration.
*/
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
{ "isLoggable", "(Ljava/lang/String;I)Z", (void*) android_util_Log_isLoggable },
{ "println_native", "(IILjava/lang/String;Ljava/lang/String;)I", (void*) android_util_Log_println_native },
diff --git a/core/jni/android_util_StringBlock.cpp b/core/jni/android_util_StringBlock.cpp
index f83eaec409d5..b396afe62dff 100644
--- a/core/jni/android_util_StringBlock.cpp
+++ b/core/jni/android_util_StringBlock.cpp
@@ -155,7 +155,7 @@ static void android_content_StringBlock_nativeDestroy(JNIEnv* env, jobject clazz
/*
* JNI registration.
*/
-static JNINativeMethod gStringBlockMethods[] = {
+static const JNINativeMethod gStringBlockMethods[] = {
/* name, signature, funcPtr */
{ "nativeCreate", "([BII)J",
(void*) android_content_StringBlock_nativeCreate },
diff --git a/core/jni/android_util_XmlBlock.cpp b/core/jni/android_util_XmlBlock.cpp
index 375710e6faca..7ae51c89fab7 100644
--- a/core/jni/android_util_XmlBlock.cpp
+++ b/core/jni/android_util_XmlBlock.cpp
@@ -364,7 +364,7 @@ static void android_content_XmlBlock_nativeDestroy(JNIEnv* env, jobject clazz,
/*
* JNI registration.
*/
-static JNINativeMethod gXmlBlockMethods[] = {
+static const JNINativeMethod gXmlBlockMethods[] = {
/* name, signature, funcPtr */
{ "nativeCreate", "([BII)J",
(void*) android_content_XmlBlock_nativeCreate },
diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp
index 0e2ec6b85209..437bd192b70a 100644
--- a/core/jni/android_view_DisplayEventReceiver.cpp
+++ b/core/jni/android_view_DisplayEventReceiver.cpp
@@ -259,7 +259,7 @@ static void nativeScheduleVsync(JNIEnv* env, jclass clazz, jlong receiverPtr) {
}
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
{ "nativeInit",
"(Ljava/lang/ref/WeakReference;Landroid/os/MessageQueue;)J",
diff --git a/core/jni/android_view_GraphicBuffer.cpp b/core/jni/android_view_GraphicBuffer.cpp
index 17d2a5eddbf8..7682dd6ca8e3 100644
--- a/core/jni/android_view_GraphicBuffer.cpp
+++ b/core/jni/android_view_GraphicBuffer.cpp
@@ -268,7 +268,7 @@ sp<GraphicBuffer> graphicBufferForJavaObject(JNIEnv* env, jobject obj) {
const char* const kClassPathName = "android/view/GraphicBuffer";
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
{ "nCreateGraphicBuffer", "(IIII)J", (void*) android_view_GraphiceBuffer_create },
{ "nDestroyGraphicBuffer", "(J)V", (void*) android_view_GraphiceBuffer_destroy },
diff --git a/core/jni/android_view_HardwareLayer.cpp b/core/jni/android_view_HardwareLayer.cpp
index 36ba892b51c4..3a0ddc9fa825 100644
--- a/core/jni/android_view_HardwareLayer.cpp
+++ b/core/jni/android_view_HardwareLayer.cpp
@@ -85,7 +85,7 @@ static void android_view_HardwareLayer_updateSurfaceTexture(JNIEnv* env, jobject
const char* const kClassPathName = "android/view/HardwareLayer";
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
{ "nPrepare", "(JIIZ)Z", (void*) android_view_HardwareLayer_prepare },
{ "nSetLayerPaint", "(JJ)V", (void*) android_view_HardwareLayer_setLayerPaint },
{ "nSetTransform", "(JJ)V", (void*) android_view_HardwareLayer_setTransform },
diff --git a/core/jni/android_view_InputChannel.cpp b/core/jni/android_view_InputChannel.cpp
index 4b42ab5d213a..092ac27176cc 100644
--- a/core/jni/android_view_InputChannel.cpp
+++ b/core/jni/android_view_InputChannel.cpp
@@ -259,7 +259,7 @@ static void android_view_InputChannel_nativeDup(JNIEnv* env, jobject obj, jobjec
// ----------------------------------------------------------------------------
-static JNINativeMethod gInputChannelMethods[] = {
+static const JNINativeMethod gInputChannelMethods[] = {
/* name, signature, funcPtr */
{ "nativeOpenInputChannelPair", "(Ljava/lang/String;)[Landroid/view/InputChannel;",
(void*)android_view_InputChannel_nativeOpenInputChannelPair },
diff --git a/core/jni/android_view_InputEventReceiver.cpp b/core/jni/android_view_InputEventReceiver.cpp
index 43b847108a20..8293cd8ff88d 100644
--- a/core/jni/android_view_InputEventReceiver.cpp
+++ b/core/jni/android_view_InputEventReceiver.cpp
@@ -395,7 +395,7 @@ static jboolean nativeConsumeBatchedInputEvents(JNIEnv* env, jclass clazz, jlong
}
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
{ "nativeInit",
"(Ljava/lang/ref/WeakReference;Landroid/view/InputChannel;Landroid/os/MessageQueue;)J",
diff --git a/core/jni/android_view_InputEventSender.cpp b/core/jni/android_view_InputEventSender.cpp
index d61dee7a7673..3bd6917aedfa 100644
--- a/core/jni/android_view_InputEventSender.cpp
+++ b/core/jni/android_view_InputEventSender.cpp
@@ -289,7 +289,7 @@ static jboolean nativeSendMotionEvent(JNIEnv* env, jclass clazz, jlong senderPtr
}
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
{ "nativeInit",
"(Ljava/lang/ref/WeakReference;Landroid/view/InputChannel;Landroid/os/MessageQueue;)J",
diff --git a/core/jni/android_view_KeyCharacterMap.cpp b/core/jni/android_view_KeyCharacterMap.cpp
index 7653f58778dd..e5519a752c39 100644
--- a/core/jni/android_view_KeyCharacterMap.cpp
+++ b/core/jni/android_view_KeyCharacterMap.cpp
@@ -203,7 +203,7 @@ static jobjectArray nativeGetEvents(JNIEnv *env, jobject clazz, jlong ptr,
* JNI registration.
*/
-static JNINativeMethod g_methods[] = {
+static const JNINativeMethod g_methods[] = {
/* name, signature, funcPtr */
{ "nativeReadFromParcel", "(Landroid/os/Parcel;)J",
(void*)nativeReadFromParcel },
diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp
index 98c17c03b1a7..81d46c3d6988 100644
--- a/core/jni/android_view_MotionEvent.cpp
+++ b/core/jni/android_view_MotionEvent.cpp
@@ -752,7 +752,7 @@ static jint android_view_MotionEvent_nativeAxisFromString(JNIEnv* env, jclass cl
// ----------------------------------------------------------------------------
-static JNINativeMethod gMotionEventMethods[] = {
+static const JNINativeMethod gMotionEventMethods[] = {
/* name, signature, funcPtr */
{ "nativeInitialize",
"(JIIIIIIIFFFFJJI[Landroid/view/MotionEvent$PointerProperties;"
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index a3b370017a8e..388d36541eb8 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -467,7 +467,7 @@ static void android_view_RenderNode_endAllAnimators(JNIEnv* env, jobject clazz,
const char* const kClassPathName = "android/view/RenderNode";
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
{ "nCreate", "(Ljava/lang/String;)J", (void*) android_view_RenderNode_create },
{ "nDestroyRenderNode", "(J)V", (void*) android_view_RenderNode_destroyRenderNode },
{ "nSetDisplayListData", "(JJ)V", (void*) android_view_RenderNode_setDisplayListData },
diff --git a/core/jni/android_view_RenderNodeAnimator.cpp b/core/jni/android_view_RenderNodeAnimator.cpp
index 4177ee2f7fe8..0926e9b76691 100644
--- a/core/jni/android_view_RenderNodeAnimator.cpp
+++ b/core/jni/android_view_RenderNodeAnimator.cpp
@@ -193,7 +193,7 @@ static void end(JNIEnv* env, jobject clazz, jlong animatorPtr) {
const char* const kClassPathName = "android/view/RenderNodeAnimator";
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
{ "nCreateAnimator", "(IF)J", (void*) createAnimator },
{ "nCreateCanvasPropertyFloatAnimator", "(JF)J", (void*) createCanvasPropertyFloatAnimator },
{ "nCreateCanvasPropertyPaintAnimator", "(JIF)J", (void*) createCanvasPropertyPaintAnimator },
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 4a311d31bd82..24055e76234e 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -514,7 +514,7 @@ static void destroy(JNIEnv* env, jclass clazz, jlong rendererPtr) {
namespace hwui = android::uirenderer;
-static JNINativeMethod gSurfaceMethods[] = {
+static const JNINativeMethod gSurfaceMethods[] = {
{"nativeCreateFromSurfaceTexture", "(Landroid/graphics/SurfaceTexture;)J",
(void*)nativeCreateFromSurfaceTexture },
{"nativeRelease", "(J)V",
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index d1acb59a6411..65ebb6633a8f 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -572,7 +572,7 @@ static jboolean nativeGetAnimationFrameStats(JNIEnv* env, jclass clazz, jobject
// ----------------------------------------------------------------------------
-static JNINativeMethod sSurfaceControlMethods[] = {
+static const JNINativeMethod sSurfaceControlMethods[] = {
{"nativeCreate", "(Landroid/view/SurfaceSession;Ljava/lang/String;IIII)J",
(void*)nativeCreate },
{"nativeRelease", "(J)V",
diff --git a/core/jni/android_view_SurfaceSession.cpp b/core/jni/android_view_SurfaceSession.cpp
index 609c565678f2..dad6958560c0 100644
--- a/core/jni/android_view_SurfaceSession.cpp
+++ b/core/jni/android_view_SurfaceSession.cpp
@@ -56,7 +56,7 @@ static void nativeKill(JNIEnv* env, jclass clazz, jlong ptr) {
}
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
{ "nativeCreate", "()J",
(void*)nativeCreate },
diff --git a/core/jni/android_view_TextureView.cpp b/core/jni/android_view_TextureView.cpp
index beb83b1e01fa..b736a17c1199 100644
--- a/core/jni/android_view_TextureView.cpp
+++ b/core/jni/android_view_TextureView.cpp
@@ -197,7 +197,7 @@ static void android_view_TextureView_unlockCanvasAndPost(JNIEnv* env, jobject,
const char* const kClassPathName = "android/view/TextureView";
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
{ "nCreateNativeWindow", "(Landroid/graphics/SurfaceTexture;)V",
(void*) android_view_TextureView_createNativeWindow },
{ "nDestroyNativeWindow", "()V",
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 6c3676b5ef05..c79f833b54a9 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -440,6 +440,32 @@ static void android_view_ThreadedRenderer_dumpProfileData(JNIEnv* env, jobject c
}
}
+static void android_view_ThreadedRenderer_addRenderNode(JNIEnv* env, jobject clazz,
+ jlong proxyPtr, jlong renderNodePtr, jboolean placeFront) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+ proxy->addRenderNode(renderNode, placeFront);
+}
+
+static void android_view_ThreadedRenderer_removeRenderNode(JNIEnv* env, jobject clazz,
+ jlong proxyPtr, jlong renderNodePtr) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+ proxy->removeRenderNode(renderNode);
+}
+
+static void android_view_ThreadedRendererd_drawRenderNode(JNIEnv* env, jobject clazz,
+ jlong proxyPtr, jlong renderNodePtr) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+ proxy->drawRenderNode(renderNode);
+}
+
+static void android_view_ThreadedRenderer_setContentOverdrawProtectionBounds(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);
+}
// ----------------------------------------------------------------------------
// Shaders
@@ -447,7 +473,6 @@ static void android_view_ThreadedRenderer_dumpProfileData(JNIEnv* env, jobject c
static void android_view_ThreadedRenderer_setupShadersDiskCache(JNIEnv* env, jobject clazz,
jstring diskCachePath) {
-
const char* cacheArray = env->GetStringUTFChars(diskCachePath, NULL);
egl_cache_t::get()->setCacheFilename(cacheArray);
env->ReleaseStringUTFChars(diskCachePath, cacheArray);
@@ -459,7 +484,7 @@ static void android_view_ThreadedRenderer_setupShadersDiskCache(JNIEnv* env, job
const char* const kClassPathName = "android/view/ThreadedRenderer";
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
{ "nSetAtlas", "(JLandroid/view/GraphicBuffer;[J)V", (void*) android_view_ThreadedRenderer_setAtlas },
{ "nSetProcessStatsBuffer", "(JI)V", (void*) android_view_ThreadedRenderer_setProcessStatsBuffer },
{ "nCreateRootRenderNode", "()J", (void*) android_view_ThreadedRenderer_createRootRenderNode },
@@ -494,6 +519,11 @@ static JNINativeMethod gMethods[] = {
{ "nDumpProfileData", "([BLjava/io/FileDescriptor;)V", (void*) android_view_ThreadedRenderer_dumpProfileData },
{ "setupShadersDiskCache", "(Ljava/lang/String;)V",
(void*) android_view_ThreadedRenderer_setupShadersDiskCache },
+ { "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},
};
int register_android_view_ThreadedRenderer(JNIEnv* env) {
diff --git a/core/jni/android_view_VelocityTracker.cpp b/core/jni/android_view_VelocityTracker.cpp
index ddd5fc853d25..04ec7059365e 100644
--- a/core/jni/android_view_VelocityTracker.cpp
+++ b/core/jni/android_view_VelocityTracker.cpp
@@ -215,7 +215,7 @@ static jboolean android_view_VelocityTracker_nativeGetEstimator(JNIEnv* env, jcl
// --- JNI Registration ---
-static JNINativeMethod gVelocityTrackerMethods[] = {
+static const JNINativeMethod gVelocityTrackerMethods[] = {
/* name, signature, funcPtr */
{ "nativeInitialize",
"(Ljava/lang/String;)J",
diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
index daa6f82ea122..364ac44ee0f6 100644
--- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
+++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
@@ -561,7 +561,7 @@ com_android_internal_content_NativeLibraryHelper_close(JNIEnv *env, jclass, jlon
delete reinterpret_cast<ZipFileRO*>(apkHandle);
}
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
{"nativeOpenApk",
"(Ljava/lang/String;)J",
(void *)com_android_internal_content_NativeLibraryHelper_openApk},
diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
index 6c0b756591f7..70134ab04a2a 100644
--- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
+++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
@@ -284,7 +284,7 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats,
return 0;
}
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
{ "nativeReadNetworkStatsDetail",
"(Landroid/net/NetworkStats;Ljava/lang/String;I[Ljava/lang/String;I)I",
(void*) readNetworkStatsDetail }
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index aef70be4922a..3f1be456c199 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -647,7 +647,7 @@ static jint com_android_internal_os_Zygote_nativeForkSystemServer(
return pid;
}
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
{ "nativeForkAndSpecialize",
"(II[II[[IILjava/lang/String;Ljava/lang/String;[ILjava/lang/String;Ljava/lang/String;)I",
(void *) com_android_internal_os_Zygote_nativeForkAndSpecialize },
diff --git a/core/jni/com_android_internal_util_VirtualRefBasePtr.cpp b/core/jni/com_android_internal_util_VirtualRefBasePtr.cpp
index 7a18c2d380ce..d20bae232656 100644
--- a/core/jni/com_android_internal_util_VirtualRefBasePtr.cpp
+++ b/core/jni/com_android_internal_util_VirtualRefBasePtr.cpp
@@ -36,7 +36,7 @@ static void decStrong(JNIEnv* env, jobject clazz, jlong objPtr) {
const char* const kClassPathName = "com/android/internal/util/VirtualRefBasePtr";
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
{ "nIncStrong", "(J)V", (void*) incStrong },
{ "nDecStrong", "(J)V", (void*) decStrong },
};
diff --git a/core/jni/com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp b/core/jni/com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp
index 2c65d6210c2e..6781e130c860 100644
--- a/core/jni/com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp
+++ b/core/jni/com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp
@@ -78,7 +78,7 @@ static jlong createLutInterpolator(JNIEnv* env, jobject clazz, jfloatArray jlut)
const char* const kClassPathName = "com/android/internal/view/animation/NativeInterpolatorFactoryHelper";
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
{ "createAccelerateDecelerateInterpolator", "()J", (void*) createAccelerateDecelerateInterpolator },
{ "createAccelerateInterpolator", "(F)J", (void*) createAccelerateInterpolator },
{ "createAnticipateInterpolator", "(F)J", (void*) createAnticipateInterpolator },
diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
index baeb7dd98bc4..3d63b013e9f1 100644
--- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
@@ -532,7 +532,7 @@ static const char *classPathName = "com/google/android/gles_jni/EGLImpl";
#define OBJECT "Ljava/lang/Object;"
#define STRING "Ljava/lang/String;"
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
{"_nativeClassInit","()V", (void*)nativeClassInit },
{"eglWaitGL", "()Z", (void*)jni_eglWaitGL },
{"eglInitialize", "(" DISPLAY "[I)Z", (void*)jni_eglInitialize },
diff --git a/core/jni/com_google_android_gles_jni_GLImpl.cpp b/core/jni/com_google_android_gles_jni_GLImpl.cpp
index f15f957d21c7..ad7d744cb693 100644
--- a/core/jni/com_google_android_gles_jni_GLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_GLImpl.cpp
@@ -8490,7 +8490,7 @@ android_glTexGenxv__IILjava_nio_IntBuffer_2
static const char *classPathName = "com/google/android/gles_jni/GLImpl";
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
{"_nativeClassInit", "()V", (void*)nativeClassInit },
{"glActiveTexture", "(I)V", (void *) android_glActiveTexture__I },
{"glAlphaFunc", "(IF)V", (void *) android_glAlphaFunc__IF },
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 921385d98bc5..c7134548a1e1 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" />
@@ -188,7 +189,7 @@
<protected-broadcast android:name="android.hardware.usb.action.USB_STATE" />
<protected-broadcast android:name="android.hardware.usb.action.USB_PORT_CHANGED" />
<protected-broadcast android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
- <protected-broadcast android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
+ <protected-broadcast android:name="android.hardware.usb.action.USB_ACCESSORY_DETACHED" />
<protected-broadcast android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
<protected-broadcast android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" />
@@ -2175,6 +2176,13 @@
<permission android:name="android.permission.CONTROL_WIFI_DISPLAY"
android:protectionLevel="signature" />
+ <!-- Allows an application to control the color transforms applied to
+ displays system-wide.
+ <p>Not for use by third-party applications.</p>
+ @hide -->
+ <permission android:name="android.permission.CONFIGURE_DISPLAY_COLOR_TRANSFORM"
+ android:protectionLevel="signature" />
+
<!-- @SystemApi Allows an application to control VPN.
<p>Not for use by third-party applications.</p>
@hide -->
diff --git a/core/res/res/color/btn_colored_material.xml b/core/res/res/color/btn_colored_background_material.xml
index b45f824c835a..b7f0ef520ff7 100644
--- a/core/res/res/color/btn_colored_material.xml
+++ b/core/res/res/color/btn_colored_background_material.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 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.
@@ -14,6 +14,7 @@
limitations under the License.
-->
+<!-- Used for tha background of a bordered colored button. -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="false"
android:alpha="?attr/disabledAlpha"
diff --git a/packages/DocumentsUI/res/layout/item_loading_grid.xml b/core/res/res/color/btn_colored_borderless_text_material.xml
index 147dfd449724..ee5a90cc8c9b 100644
--- a/packages/DocumentsUI/res/layout/item_loading_grid.xml
+++ b/core/res/res/color/btn_colored_borderless_text_material.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 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.
@@ -14,16 +14,10 @@
limitations under the License.
-->
-<com.android.documentsui.GridItem xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="@dimen/grid_height"
- android:orientation="horizontal">
-
- <ProgressBar
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:indeterminate="true"
- style="?android:attr/progressBarStyle" />
-
-</com.android.documentsui.GridItem>
+<!-- Used for the text of a borderless colored button. -->
+<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/colorAccent"/>
+</selector>
diff --git a/core/res/res/color/btn_colored_text_material.xml b/core/res/res/color/btn_colored_text_material.xml
index 950d04a68b45..23d05a9bafd6 100644
--- a/core/res/res/color/btn_colored_text_material.xml
+++ b/core/res/res/color/btn_colored_text_material.xml
@@ -14,9 +14,10 @@
limitations under the License.
-->
+<!-- Used for the text of a bordered colored button. -->
<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/colorAccent"/>
+ <item android:color="?attr/textColorSecondaryInverse" />
</selector>
diff --git a/core/res/res/drawable/btn_colored_material.xml b/core/res/res/drawable/btn_colored_material.xml
index 81cbe393bf80..c3c5760f2cc5 100644
--- a/core/res/res/drawable/btn_colored_material.xml
+++ b/core/res/res/drawable/btn_colored_material.xml
@@ -22,7 +22,7 @@
<ripple android:color="?attr/colorControlHighlight">
<item>
<shape android:shape="rectangle"
- android:tint="@color/btn_colored_material">
+ android:tint="@color/btn_colored_background_material">
<corners android:radius="@dimen/control_corner_material" />
<solid android:color="@color/white" />
<padding android:left="@dimen/button_padding_horizontal_material"
diff --git a/core/res/res/layout-land/time_picker_material.xml b/core/res/res/layout-land/time_picker_material.xml
index 2473e875bf65..bb347cb249b8 100644
--- a/core/res/res/layout-land/time_picker_material.xml
+++ b/core/res/res/layout-land/time_picker_material.xml
@@ -46,7 +46,8 @@
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_centerInParent="true"
- android:paddingTop="@dimen/timepicker_radial_picker_top_margin">
+ android:paddingTop="@dimen/timepicker_radial_picker_top_margin"
+ android:layout_marginBottom="-12dp">
<!-- The hour should always be to the left of the separator,
regardless of the current locale's layout direction. -->
@@ -57,14 +58,16 @@
android:textAppearance="@style/TextAppearance.Material.TimePicker.TimeLabel"
android:singleLine="true"
android:ellipsize="none"
- android:gravity="right" />
+ android:gravity="right"
+ android:includeFontPadding="false" />
<TextView
android:id="@+id/separator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.Material.TimePicker.TimeLabel"
- android:importantForAccessibility="no" />
+ android:importantForAccessibility="no"
+ android:includeFontPadding="false" />
<!-- The minutes should always be to the right of the separator,
regardless of the current locale's layout direction. -->
@@ -75,7 +78,8 @@
android:textAppearance="@style/TextAppearance.Material.TimePicker.TimeLabel"
android:singleLine="true"
android:ellipsize="none"
- android:gravity="left" />
+ android:gravity="left"
+ android:includeFontPadding="false" />
</LinearLayout>
<!-- The layout alignment of this view will switch between toRightOf
@@ -93,22 +97,27 @@
android:id="@+id/am_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:minHeight="48dp"
+ android:minWidth="48dp"
+ android:gravity="bottom"
android:textAppearance="@style/TextAppearance.Material.TimePicker.AmPmLabel"
android:paddingStart="@dimen/timepicker_ampm_horizontal_padding"
android:paddingEnd="@dimen/timepicker_ampm_horizontal_padding"
- android:paddingTop="@dimen/timepicker_am_top_padding"
+ android:paddingTop="4dp"
+ android:paddingBottom="6dp"
android:lines="1"
- android:ellipsize="none"
- android:includeFontPadding="false" />
+ android:ellipsize="none" />
<CheckedTextView
android:id="@+id/pm_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:minHeight="48dp"
+ android:minWidth="48dp"
+ android:gravity="top"
android:textAppearance="@style/TextAppearance.Material.TimePicker.AmPmLabel"
android:paddingStart="@dimen/timepicker_ampm_horizontal_padding"
android:paddingEnd="@dimen/timepicker_ampm_horizontal_padding"
- android:paddingTop="@dimen/timepicker_pm_top_padding"
android:lines="1"
android:ellipsize="none"
android:includeFontPadding="false" />
diff --git a/packages/DocumentsUI/res/layout/item_loading_list.xml b/core/res/res/layout/docked_stack_divider.xml
index 6f214edea8c4..aa6e68d57af9 100644
--- a/packages/DocumentsUI/res/layout/item_loading_list.xml
+++ b/core/res/res/layout/docked_stack_divider.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 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.
@@ -15,15 +15,7 @@
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:minHeight="@dimen/list_item_height">
-
- <ProgressBar
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:indeterminate="true"
- style="?android:attr/progressBarStyle" />
-
-</FrameLayout>
+ android:layout_width="@dimen/docked_stack_divider_thickness"
+ android:layout_height="match_parent"
+ android:background="@android:color/black"
+ />
diff --git a/core/res/res/layout/number_picker_material.xml b/core/res/res/layout/number_picker_material.xml
index 47edec475aa7..b0455857e79e 100644
--- a/core/res/res/layout/number_picker_material.xml
+++ b/core/res/res/layout/number_picker_material.xml
@@ -22,4 +22,4 @@
android:gravity="center"
android:singleLine="true"
android:background="@null"
- android:textAppearance="@style/TextAppearance.Material.Caption" />
+ android:textAppearance="@style/TextAppearance.Material.Body1" />
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/layout/time_picker_header_material.xml b/core/res/res/layout/time_picker_header_material.xml
index 3c3a8a8ff3ed..acdc5090f41e 100644
--- a/core/res/res/layout/time_picker_header_material.xml
+++ b/core/res/res/layout/time_picker_header_material.xml
@@ -78,6 +78,9 @@
android:id="@+id/am_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:minWidth="48dp"
+ android:minHeight="48dp"
+ android:gravity="bottom"
android:paddingTop="@dimen/timepicker_am_top_padding"
android:textAppearance="@style/TextAppearance.Material.TimePicker.AmPmLabel"
android:lines="1"
@@ -86,6 +89,9 @@
android:id="@+id/pm_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:minWidth="48dp"
+ android:minHeight="48dp"
+ android:gravity="top"
android:paddingTop="@dimen/timepicker_pm_top_padding"
android:textAppearance="@style/TextAppearance.Material.TimePicker.AmPmLabel"
android:lines="1"
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-mcc240-mnc01/config.xml b/core/res/res/values-mcc240-mnc01/config.xml
new file mode 100644
index 000000000000..7fb5c46309d0
--- /dev/null
+++ b/core/res/res/values-mcc240-mnc01/config.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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 my 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+ for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- Do not set the system language as value of EF LI/EF PL -->
+ <bool name="config_use_sim_language_file">false</bool>
+
+</resources>
diff --git a/core/res/res/values-mcc240-mnc05/config.xml b/core/res/res/values-mcc240-mnc05/config.xml
new file mode 100644
index 000000000000..7fb5c46309d0
--- /dev/null
+++ b/core/res/res/values-mcc240-mnc05/config.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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 my 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+ for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- Do not set the system language as value of EF LI/EF PL -->
+ <bool name="config_use_sim_language_file">false</bool>
+
+</resources>
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..af80ed322c61 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..488470f7c46a 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>
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 48bfe28fb89a..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>
<!-- ============================= -->
@@ -5550,6 +5562,8 @@ i
<!-- Push object to the end of its container, not changing its size. -->
<flag name="end" value="0x00800005" />
</attr>
+ <!-- Specifies the initial drawable level in the range 0 to 10000. -->
+ <attr name="level" format="integer" />
<!-- Reference to a drawable resource to draw with the specified scale. -->
<attr name="drawable" />
<!-- Use the drawable's intrinsic width and height as minimum size values.
@@ -7769,10 +7783,24 @@ i
<attr name="title" />
<attr name="subtitle" />
<attr name="gravity" />
- <attr name="titleMargins" format="dimension" />
+ <!-- Specifies extra space on the left, start, right and end sides
+ of the toolbar's title. Margin values should be positive. -->
+ <attr name="titleMargin" format="dimension" />
+ <!-- Specifies extra space on the start side of the toolbar's title.
+ If both this attribute and titleMargin are specified, then this
+ attribute takes precedence. Margin values should be positive. -->
<attr name="titleMarginStart" format="dimension" />
+ <!-- Specifies extra space on the end side of the toolbar's title.
+ If both this attribute and titleMargin are specified, then this
+ attribute takes precedence. Margin values should be positive. -->
<attr name="titleMarginEnd" format="dimension" />
+ <!-- Specifies extra space on the top side of the toolbar's title.
+ If both this attribute and titleMargin are specified, then this
+ attribute takes precedence. Margin values should be positive. -->
<attr name="titleMarginTop" format="dimension" />
+ <!-- Specifies extra space on the bottom side of the toolbar's title.
+ If both this attribute and titleMargin are specified, then this
+ attribute takes precedence. Margin values should be positive. -->
<attr name="titleMarginBottom" format="dimension" />
<attr name="contentInsetStart" />
<attr name="contentInsetEnd" />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index a5960a9571a0..24d760fddbf8 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -410,6 +410,9 @@
radio is unable to find any MCC information to infer wifi country code from -->
<bool translatable="false" name="config_wifi_revert_country_code_on_cellular_loss">false</bool>
+ <!-- Boolean indicating whether or not wifi firmware debugging is enabled -->
+ <bool translatable="false" name="config_wifi_enable_wifi_firmware_debugging">false</bool>
+
<!-- Integer specifying the basic autojoin parameters -->
<integer translatable="false" name="config_wifi_framework_5GHz_preference_boost_threshold">-65</integer>
<integer translatable="false" name="config_wifi_framework_5GHz_preference_boost_factor">5</integer>
@@ -1759,6 +1762,28 @@
-->
<bool name="config_enableWifiDisplay">false</bool>
+ <!-- The color transform values that correspond to each respective configuration mode for the
+ built-in display, or -1 if the mode is unsupported by the device. The possible
+ configuration modes are:
+ 1. Wide-gamut ("Vibrant")
+ 2. Adobe RGB ("Natural")
+ 3. sRGB ("Standard")
+
+ For example, if a device had Wide-gamut as color transform mode 1, sRGB mode as color
+ transform mode 7, and did not support Adobe RGB at all this would look like:
+
+ <integer-array name="config_colorTransforms">
+ <item>1</item>
+ <item>-1</item>
+ <item>7</item>
+ </integer-array>
+ -->
+ <integer-array name="config_colorTransforms">
+ <item>-1</item>
+ <item>-1</item>
+ <item>-1</item>
+ </integer-array>
+
<!-- When true use the linux /dev/input/event subsystem to detect the switch changes
on the headphone/microphone jack. When false use the older uevent framework. -->
<bool name="config_useDevInputEventForAudioJack">false</bool>
@@ -2189,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.xml b/core/res/res/values/dimens.xml
index 8635a4fac7bc..2621bc9cf219 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -45,6 +45,9 @@
<!-- Margin at the edge of the screen to ignore touch events for in the windowshade. -->
<dimen name="status_bar_edge_ignore">5dp</dimen>
+ <!-- Width of a divider bar used to resize docked stacks. -->
+ <dimen name="docked_stack_divider_thickness">24dp</dimen>
+
<!-- Min width for a tablet device -->
<dimen name="min_xlarge_screen_width">800dp</dimen>
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 a2b6a7bd49a2..f4d0b398561f 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2662,6 +2662,20 @@
<public type="attr" name="listMenuViewStyle" />
<public type="attr" name="subMenuArrow" />
+ <public type="attr" name="activityWidth" />
+ <public type="attr" name="activityHeight" />
+ <public type="attr" name="resizeableActivity" />
+ <public type="attr" name="titleMargin" />
+ <public type="attr" name="titleMarginStart" />
+ <public type="attr" name="titleMarginEnd" />
+ <public type="attr" name="titleMarginTop" />
+ <public type="attr" name="titleMarginBottom" />
+ <public type="attr" name="maxButtonHeight" />
+ <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" />
@@ -2682,8 +2696,5 @@
<public type="style" name="Theme.Material.DayNight.DialogWhenLarge.DarkActionBar" />
<public type="id" name="accessibilityActionSetProgress" />
- <public type="attr" name="activityWidth" />
- <public type="attr" name="activityHeight" />
- <public type="attr" name="resizeableActivity" />
</resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 4bad16d236cd..11c4cc01ee82 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1232,7 +1232,7 @@ please see styles_device_defaults.xml.
<item name="titleTextAppearance">@style/TextAppearance.Widget.Toolbar.Title</item>
<item name="subtitleTextAppearance">@style/TextAppearance.Widget.Toolbar.Subtitle</item>
<item name="minHeight">?attr/actionBarSize</item>
- <item name="titleMargins">4dp</item>
+ <item name="titleMargin">4dp</item>
<item name="maxButtonHeight">56dp</item>
<item name="buttonGravity">top</item>
<item name="navigationButtonStyle">@style/Widget.Toolbar.Button.Navigation</item>
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index 5dc14e301704..38a1693141dc 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -307,6 +307,10 @@ 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" parent="TextAppearance.Material.Subhead">
+ <item name="fontFamily">@string/font_family_title_material</item>
+ <item name="textSize">@dimen/text_size_menu_header_material</item>
+ </style>
<style name="TextAppearance.Material.Widget.DropDownHint" parent="TextAppearance.Material.Menu" />
@@ -471,6 +475,7 @@ please see styles_device_defaults.xml.
<style name="Widget.Material.Button.Colored">
<item name="background">@drawable/btn_colored_material</item>
<item name="textAppearance">@style/TextAppearance.Material.Widget.Button.Inverse</item>
+ <item name="textColor">@color/btn_colored_text_material</item>
</style>
<!-- Small bordered ink button -->
@@ -487,7 +492,7 @@ please see styles_device_defaults.xml.
<!-- Colored borderless ink button -->
<style name="Widget.Material.Button.Borderless.Colored">
- <item name="textColor">@color/btn_colored_text_material</item>
+ <item name="textColor">@color/btn_colored_borderless_text_material</item>
</style>
<!-- Alert dialog button bar button -->
@@ -862,6 +867,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 16e44b861790..06de81d1081e 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -307,6 +307,7 @@
<java-symbol type="bool" name="config_wifi_enable_disconnection_debounce" />
<java-symbol type="bool" name="config_wifi_enable_5GHz_preference" />
<java-symbol type="bool" name="config_wifi_revert_country_code_on_cellular_loss" />
+ <java-symbol type="bool" name="config_wifi_enable_wifi_firmware_debugging" />
<java-symbol type="bool" name="config_supportMicNearUltrasound" />
<java-symbol type="bool" name="config_supportSpeakerNearUltrasound" />
<java-symbol type="integer" name="config_wifi_framework_5GHz_preference_boost_threshold" />
@@ -1133,6 +1134,7 @@
<java-symbol type="array" name="config_telephonyHardware" />
<java-symbol type="array" name="config_keySystemUuidMapping" />
<java-symbol type="array" name="config_gpsParameters" />
+ <java-symbol type="array" name="config_colorTransforms" />
<java-symbol type="drawable" name="default_wallpaper" />
<java-symbol type="drawable" name="indicator_input_error" />
@@ -1288,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" />
@@ -1476,6 +1479,7 @@
<java-symbol type="bool" name="config_showNavigationBar" />
<java-symbol type="bool" name="config_supportAutoRotation" />
<java-symbol type="bool" name="target_honeycomb_needs_options_menu" />
+ <java-symbol type="dimen" name="docked_stack_divider_thickness" />
<java-symbol type="dimen" name="navigation_bar_height" />
<java-symbol type="dimen" name="navigation_bar_height_landscape" />
<java-symbol type="dimen" name="navigation_bar_width" />
@@ -1718,6 +1722,7 @@
<java-symbol type="integer" name="config_undockedHdmiRotation" />
<java-symbol type="integer" name="config_virtualKeyQuietTimeMillis" />
<java-symbol type="layout" name="am_compat_mode_dialog" />
+ <java-symbol type="layout" name="docked_stack_divider" />
<java-symbol type="layout" name="launch_warning" />
<java-symbol type="layout" name="safe_mode" />
<java-symbol type="layout" name="simple_list_item_2_single_choice" />
@@ -2187,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/res/res/xml/power_profile.xml b/core/res/res/xml/power_profile.xml
index 28d99d8784db..ddd0ca2a4bb2 100644
--- a/core/res/res/xml/power_profile.xml
+++ b/core/res/res/xml/power_profile.xml
@@ -47,17 +47,38 @@
<value>0.2</value> <!-- ~2mA -->
<value>0.1</value> <!-- ~1mA -->
</array>
- <!-- Different CPU speeds as reported in
- /sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state -->
- <array name="cpu.speeds">
+
+ <!-- A list of heterogeneous CPU clusters, where the value for each cluster represents the
+ number of CPU cores for that cluster.
+
+ Ex:
+ <array name="cpu.clusters.cores">
+ <value>4</value> // cluster 0 has cpu0, cpu1, cpu2, cpu3
+ <value>2</value> // cluster 1 has cpu4, cpu5
+ </array> -->
+ <array name="cpu.clusters.cores">
+ <value>1</value> <!-- cluster 0 has cpu0 -->
+ </array>
+
+ <!-- Different CPU speeds for cluster 0 as reported in
+ /sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state.
+
+ There must be one of these for each cluster, labeled:
+ cpu.speeds.cluster0, cpu.speeds.cluster1, etc... -->
+ <array name="cpu.speeds.cluster0">
<value>400000</value> <!-- 400 MHz CPU speed -->
</array>
- <!-- Current when CPU is idle -->
- <item name="cpu.idle">0.1</item>
- <!-- Current at each CPU speed, as per 'cpu.speeds' -->
- <array name="cpu.active">
+
+ <!-- Current at each CPU speed for cluster 0, as per 'cpu.speeds.cluster0'.
+ Like cpu.speeds.cluster0, there must be one of these present for
+ each heterogeneous CPU cluster. -->
+ <array name="cpu.active.cluster0">
<value>0.1</value> <!-- ~100mA -->
</array>
+
+ <!-- Current when CPU is idle -->
+ <item name="cpu.idle">0.1</item>
+
<!-- This is the battery capacity in mAh (measured at nominal voltage) -->
<item name="battery.capacity">1000</item>
diff --git a/core/tests/BTtraffic/Android.mk b/core/tests/BTtraffic/Android.mk
new file mode 100644
index 000000000000..7d8352717a34
--- /dev/null
+++ b/core/tests/BTtraffic/Android.mk
@@ -0,0 +1,16 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_RESOURCE_DIR := \
+ $(LOCAL_PATH)/res
+
+LOCAL_PACKAGE_NAME := bttraffic
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/core/tests/BTtraffic/AndroidManifest.xml b/core/tests/BTtraffic/AndroidManifest.xml
new file mode 100644
index 000000000000..00d9707de2bf
--- /dev/null
+++ b/core/tests/BTtraffic/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.google.android.experimental.bttraffic" >
+
+ <uses-permission android:name="android.permission.BLUETOOTH"/>
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
+
+ <uses-sdk
+ android:minSdkVersion="18"
+ android:targetSdkVersion="18"
+ />
+ <application
+ android:allowBackup="false"
+ android:label="@string/app_name" >
+ <service
+ android:name=".BTtraffic"
+ android:enabled="true"
+ android:exported="true" >
+ </service>
+ </application>
+
+</manifest>
diff --git a/core/tests/BTtraffic/README b/core/tests/BTtraffic/README
new file mode 100644
index 000000000000..430488f656f9
--- /dev/null
+++ b/core/tests/BTtraffic/README
@@ -0,0 +1,45 @@
+This is a tool to generate classic Bluetooth traffic with specified period and package size.
+Together with the SvcMonitor, which will be called automatically in this android service, can be
+used to measure the CPU usage from the Java layer Bluetooth code and the underlying system service
+com.android.bluetooth.
+
+1. Server (Listener) - Client (Sender) model. Both run as an Android service.
+2. No pairing needed. Communicate via unsecured RFcomm. Client establishes the connection by
+providing the MAC addr of the server.
+3. Bluetooth has to be turned on on both side.
+4. Client can configure the traffic by specifying the transfer period and package size.
+5. A separate monitor process will be automatically forked and will be reading from /proc file
+system to calculate the cpu usage. The measurement is updated once per second.
+6. The monitor process (com.google.android.experimental.svcmonitor/.ScvMonitor) can be run as an
+independent service to measure cpu usage on any similarly configured tests (e.g. wifi, BLE). Refer
+to SvcMonitor's README for usage and details.
+
+Usage:
+To instal the test:
+On both the server and client device, install the 2 apk:
+$ adb install $OUT/system/app/bttraffic/bttraffic.apk
+$ adb install $OUT/system/app/svcmonitor/svcmonitor.apk
+
+To start the service on the SERVER side:
+$ adb shell am startservice -a start --ez ack true \
+com.google.android.experimental.bttraffic/.BTtraffic
+
+To start the service on the CLIENT side:
+$ adb shell am startservice -a start \
+-e addr "F8:A9:D0:A8:74:8E" --ei size 1000 --ei period 15 \
+com.google.android.experimental.bttraffic/.BTtraffic
+
+To stop the test:
+On either the server or client:
+$ adb shell am startservice -a stop \
+com.google.android.experimental.bttraffic/.BTtraffic
+
+To look at the data:
+$ adb logcat | grep bttraffic
+
+Options:
+-e addr: MAC addr of the server, in uppercase letter.
+--ei size: package size, unit: byte; default: 1024, MAX: 20MB
+--ei period: system sleep time between sending each package, unit: ms, default: 5000
+ ** if -1 is provided, client will only send the package once.
+--ez ack: whether acknowledge is required (true/false)
diff --git a/core/tests/BTtraffic/res/values/strings.xml b/core/tests/BTtraffic/res/values/strings.xml
new file mode 100644
index 000000000000..e70276e03647
--- /dev/null
+++ b/core/tests/BTtraffic/res/values/strings.xml
@@ -0,0 +1,3 @@
+<resources>
+ <string name="app_name">Bluetooth Test</string>
+</resources>
diff --git a/core/tests/BTtraffic/src/com/android/google/experimental/bttraffic/BTtraffic.java b/core/tests/BTtraffic/src/com/android/google/experimental/bttraffic/BTtraffic.java
new file mode 100644
index 000000000000..286c0aa2915f
--- /dev/null
+++ b/core/tests/BTtraffic/src/com/android/google/experimental/bttraffic/BTtraffic.java
@@ -0,0 +1,328 @@
+package com.google.android.experimental.bttraffic;
+
+import android.app.Service;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothServerSocket;
+import android.bluetooth.BluetoothSocket;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.SystemClock;
+import android.util.Log;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.Exception;
+import java.lang.Runtime;
+import java.lang.RuntimeException;
+import java.lang.Process;
+import java.nio.ByteBuffer;
+import java.util.Random;
+import java.util.Set;
+import java.util.UUID;
+
+public class BTtraffic extends Service {
+ public static final String TAG = "bttraffic";
+ static final String SERVICE_NAME = "bttraffic";
+ static final String SYS_SERVICE_NAME = "com.android.bluetooth";
+ static final UUID SERVICE_UUID = UUID.fromString("5e8945b0-1234-5432-a5e2-0800200c9a67");
+ volatile Thread mWorkerThread;
+ volatile boolean isShuttingDown = false;
+ volatile boolean isServer = false;
+
+ public BTtraffic() {}
+
+ static void safeClose(Closeable closeable) {
+ try {
+ closeable.close();
+ } catch (IOException e) {
+ Log.d(TAG, "Unable to close resource.\n");
+ }
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ if (intent == null) {
+ stopSelf();
+ return 0;
+ }
+ if ("stop".equals(intent.getAction())) {
+ stopService();
+ } else if ("start".equals(intent.getAction())) {
+ startWorker(intent);
+ } else {
+ Log.d(TAG, "unknown action: + " + intent.getAction());
+ }
+ return 0;
+ }
+
+ private void startWorker(Intent intent) {
+ if (mWorkerThread != null) {
+ Log.d(TAG, "worker thread already active");
+ return;
+ }
+ isShuttingDown = false;
+ String remoteAddr = intent.getStringExtra("addr");
+ Log.d(TAG, "startWorker: addr=" + remoteAddr);
+ Runnable worker =
+ remoteAddr == null
+ ? new ListenerRunnable(this, intent)
+ : new SenderRunnable(this, remoteAddr, intent);
+ isServer = remoteAddr == null ? true: false;
+ mWorkerThread = new Thread(worker, "BTtrafficWorker");
+ try {
+ startMonitor();
+ Log.d(TAG, "Monitor service started");
+ mWorkerThread.start();
+ Log.d(TAG, "Worker thread started");
+ } catch (Exception e) {
+ Log.d(TAG, "Failed to start service", e);
+ }
+ }
+
+ private void startMonitor()
+ throws Exception {
+ if (isServer) {
+ Log.d(TAG, "Start monitor on server");
+ String[] startmonitorCmd = {
+ "/system/bin/am",
+ "startservice",
+ "-a", "start",
+ "-e", "java", SERVICE_NAME,
+ "-e", "hal", SYS_SERVICE_NAME,
+ "com.google.android.experimental.svcmonitor/.SvcMonitor"
+ };
+ Process ps = new ProcessBuilder()
+ .command(startmonitorCmd)
+ .redirectErrorStream(true)
+ .start();
+ } else {
+ Log.d(TAG, "No need to start SvcMonitor on client");
+ }
+ }
+
+ private void stopMonitor()
+ throws Exception {
+ if (isServer) {
+ Log.d(TAG, "StopMonitor on server");
+ String[] stopmonitorCmd = {
+ "/system/bin/am",
+ "startservice",
+ "-a", "stop",
+ "com.google.android.experimental.svcmonitor/.SvcMonitor"
+ };
+ Process ps = new ProcessBuilder()
+ .command(stopmonitorCmd)
+ .redirectErrorStream(true)
+ .start();
+ } else {
+ Log.d(TAG, "No need to stop Svcmonitor on client");
+ }
+ }
+
+ public void stopService() {
+ if (mWorkerThread == null) {
+ Log.d(TAG, "no active thread");
+ return;
+ }
+
+ isShuttingDown = true;
+
+ try {
+ stopMonitor();
+ } catch (Exception e) {
+ Log.d(TAG, "Unable to stop SvcMonitor!", e);
+ }
+
+ if (Thread.currentThread() != mWorkerThread) {
+ mWorkerThread.interrupt();
+ Log.d(TAG, "Interrupting thread");
+ try {
+ mWorkerThread.join();
+ } catch (InterruptedException e) {
+ Log.d(TAG, "Unable to join thread!");
+ }
+ }
+
+ mWorkerThread = null;
+ stopSelf();
+ Log.d(TAG, "Service stopped");
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ throw new UnsupportedOperationException("Not yet implemented");
+ }
+
+ public static class ListenerRunnable implements Runnable {
+ private final BTtraffic bttraffic;
+ private final boolean sendAck;
+ private Intent intent;
+ private final int maxbuffersize = 20 * 1024 * 1024;
+
+ public ListenerRunnable(BTtraffic bttraffic, Intent intent) {
+ this.bttraffic = bttraffic;
+ this.sendAck = intent.getBooleanExtra("ack", true);
+ this.intent = intent;
+ }
+
+ @Override
+ public void run() {
+ BluetoothServerSocket serverSocket;
+
+ try {
+ Log.d(TAG, "getting server socket");
+ serverSocket = BluetoothAdapter.getDefaultAdapter()
+ .listenUsingInsecureRfcommWithServiceRecord(
+ SERVICE_NAME, SERVICE_UUID);
+ } catch (IOException e) {
+ Log.d(TAG, "error creating server socket, stopping thread");
+ bttraffic.stopService();
+ return;
+ }
+
+ Log.d(TAG, "got server socket, starting accept loop");
+ BluetoothSocket socket = null;
+ try {
+ Log.d(TAG, "accepting");
+ socket = serverSocket.accept();
+
+ if (!Thread.interrupted()) {
+ Log.d(TAG, "accepted, listening");
+ doListening(socket.getInputStream(), socket.getOutputStream());
+ Log.d(TAG, "listen finished");
+ }
+ } catch (IOException e) {
+ Log.d(TAG, "error while accepting or listening", e);
+ } finally {
+ Log.d(TAG, "Linster interruped");
+ Log.d(TAG, "closing socket and stopping service");
+ safeClose(serverSocket);
+ safeClose(socket);
+ if (!bttraffic.isShuttingDown)
+ bttraffic.stopService();
+ }
+
+ }
+
+ private void doListening(InputStream inputStream, OutputStream outputStream)
+ throws IOException {
+ ByteBuffer byteBuffer = ByteBuffer.allocate(maxbuffersize);
+
+ while (!Thread.interrupted()) {
+ readBytesIntoBuffer(inputStream, byteBuffer, 4);
+ byteBuffer.flip();
+ int length = byteBuffer.getInt();
+ if (Thread.interrupted())
+ break;
+ readBytesIntoBuffer(inputStream, byteBuffer, length);
+
+ if (sendAck)
+ outputStream.write(0x55);
+ }
+ }
+
+ void readBytesIntoBuffer(InputStream inputStream, ByteBuffer byteBuffer, int numToRead)
+ throws IOException {
+ byteBuffer.clear();
+ while (true) {
+ int position = byteBuffer.position();
+ int remaining = numToRead - position;
+ if (remaining == 0) {
+ break;
+ }
+ int count = inputStream.read(byteBuffer.array(), position, remaining);
+ if (count < 0) {
+ throw new IOException("read the EOF");
+ }
+ byteBuffer.position(position + count);
+ }
+ }
+ }
+
+ public static class SenderRunnable implements Runnable {
+ private final BTtraffic bttraffic;
+ private final String remoteAddr;
+ private final int pkgsize, period;
+ private final int defaultpkgsize = 1024;
+ private final int defaultperiod = 5000;
+ private static ByteBuffer lengthBuffer = ByteBuffer.allocate(4);
+
+ public SenderRunnable(BTtraffic bttraffic, String remoteAddr, Intent intent) {
+ this.bttraffic = bttraffic;
+ this.remoteAddr = remoteAddr;
+ this.pkgsize = intent.getIntExtra("size", defaultpkgsize);
+ this.period = intent.getIntExtra("period", defaultperiod);
+ }
+
+ @Override
+ public void run() {
+ BluetoothDevice device = null;
+ try {
+ device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(remoteAddr);
+ } catch (IllegalArgumentException e) {
+ Log.d(TAG, "Invalid BT MAC address!\n");
+ }
+ if (device == null) {
+ Log.d(TAG, "can't find matching device, stopping thread and service");
+ bttraffic.stopService();
+ return;
+ }
+
+ BluetoothSocket socket = null;
+ try {
+ Log.d(TAG, "connecting to device with MAC addr: " + remoteAddr);
+ socket = device.createInsecureRfcommSocketToServiceRecord(SERVICE_UUID);
+ socket.connect();
+ Log.d(TAG, "connected, starting to send");
+ doSending(socket.getOutputStream());
+ Log.d(TAG, "send stopped, stopping service");
+ } catch (Exception e) {
+ Log.d(TAG, "error while sending", e);
+ } finally {
+ Log.d(TAG, "finishing, closing thread and service");
+ safeClose(socket);
+ if (!bttraffic.isShuttingDown)
+ bttraffic.stopService();
+ }
+ }
+
+ private void doSending(OutputStream outputStream) throws IOException {
+ Log.w(TAG, "doSending");
+ try {
+ Random random = new Random(System.currentTimeMillis());
+
+ byte[] bytes = new byte[pkgsize];
+ random.nextBytes(bytes);
+ while (!Thread.interrupted()) {
+ writeBytes(outputStream, bytes.length);
+ outputStream.write(bytes, 0, bytes.length);
+ if (period < 0)
+ break;
+ if (period == 0)
+ continue;
+
+ SystemClock.sleep(period);
+ }
+ Log.d(TAG, "Sender interrupted");
+ } catch (IOException e) {
+ Log.d(TAG, "doSending got error", e);
+ }
+ }
+
+ private static void writeBytes(OutputStream outputStream, int value) throws IOException {
+ lengthBuffer.putInt(value);
+ lengthBuffer.flip();
+ outputStream.write(lengthBuffer.array(), lengthBuffer.position(), lengthBuffer.limit());
+ }
+ }
+
+}
diff --git a/core/tests/SvcMonitor/Android.mk b/core/tests/SvcMonitor/Android.mk
new file mode 100644
index 000000000000..2b8045506f02
--- /dev/null
+++ b/core/tests/SvcMonitor/Android.mk
@@ -0,0 +1,16 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_RESOURCE_DIR := \
+ $(LOCAL_PATH)/res
+
+LOCAL_PACKAGE_NAME := svcmonitor
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/core/tests/SvcMonitor/AndroidManifest.xml b/core/tests/SvcMonitor/AndroidManifest.xml
new file mode 100644
index 000000000000..de5a9bdaed41
--- /dev/null
+++ b/core/tests/SvcMonitor/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.google.android.experimental.svcmonitor" >
+
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
+
+ <uses-sdk
+ android:minSdkVersion="18"
+ android:targetSdkVersion="18"
+ />
+ <application
+ android:allowBackup="false"
+ android:label="@string/app_name" >
+ <service
+ android:name=".SvcMonitor"
+ android:enabled="true"
+ android:exported="true" >
+ </service>
+ </application>
+
+</manifest>
diff --git a/core/tests/SvcMonitor/README b/core/tests/SvcMonitor/README
new file mode 100644
index 000000000000..13a4380589b4
--- /dev/null
+++ b/core/tests/SvcMonitor/README
@@ -0,0 +1,27 @@
+This Android service measures CPU usage of a program and an underlying system service it relies on.
+An example of this would be an android app XYZ communicates to some other device via Bluetooth. The
+SvcMonitor service can monitor the CPU usage of XYZ and com.android.bluetooth.
+
+Usage:
+
+To start the service:
+$ adb shell am startservice -a start \
+-e java XYZ -e hal com.android.bluetooth \
+com.google.android.experimental.svcmonitor/.SvcMonitor
+
+To stop the service:
+$ adb shell am startservice -a stop \
+com.google.android.experimental.svcmonitor/.SvcMonitor
+
+To stop the service config:
+$ adb shell am startservice -a change \
+-e java NewName -e hal NewService \
+com.google.android.experimental.svcmonitor/.SvcMonitor
+
+To monitor the data:
+$ adb logcat | grep XYZ
+
+Options:
+-e java NameOfProgram: any running process’s name.
+-e hal NameOfSysService: name of the system service the previous process relies on.
+--ei period: period between each measurement (frequency). Unit: ms, Default:1000, Min: 100
diff --git a/core/tests/SvcMonitor/res/values/strings.xml b/core/tests/SvcMonitor/res/values/strings.xml
new file mode 100644
index 000000000000..e70276e03647
--- /dev/null
+++ b/core/tests/SvcMonitor/res/values/strings.xml
@@ -0,0 +1,3 @@
+<resources>
+ <string name="app_name">Bluetooth Test</string>
+</resources>
diff --git a/core/tests/SvcMonitor/src/com/android/google/experimental/svcmoniter/SvcMonitor.java b/core/tests/SvcMonitor/src/com/android/google/experimental/svcmoniter/SvcMonitor.java
new file mode 100644
index 000000000000..a451445530cd
--- /dev/null
+++ b/core/tests/SvcMonitor/src/com/android/google/experimental/svcmoniter/SvcMonitor.java
@@ -0,0 +1,209 @@
+package com.google.android.experimental.svcmonitor;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.SystemClock;
+import android.util.Log;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.lang.Runnable;
+import java.lang.Thread;
+import java.util.Set;
+
+public class SvcMonitor extends Service {
+ public static final String TAG = "svcmonitor";
+ String javaProc, halProc;
+ volatile Thread tMonitor;
+ int period;
+
+ public SvcMonitor() {};
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ if (intent == null) {
+ stopSelf();
+ return 0;
+ }
+ Log.d(TAG, "Starting SvcMonitor");
+ if ("stop".equals(intent.getAction())) {
+ stopService();
+ } else if ("start".equals(intent.getAction())) {
+ startMonitor(intent);
+ } else if ("change".equals(intent.getAction())) {
+ changeConfig(intent);
+ } else {
+ Log.d(TAG, "unknown action: + " + intent.getAction());
+ }
+ return 0;
+ }
+
+ private void changeConfig(Intent intent) {
+ if (tMonitor == null) {
+ Log.d(TAG, "Service not active. Start service first");
+ return;
+ }
+ stopThread();
+ startMonitor(intent);
+ }
+
+ private void startMonitor(Intent intent) {
+ if (tMonitor != null) {
+ Log.d(TAG, "thread already active");
+ return;
+ }
+ javaProc = intent.getStringExtra("java");
+ halProc = intent.getStringExtra("hal");
+ period = intent.getIntExtra("period", 1000);
+ if (javaProc == null || halProc == null || period < 100) {
+ Log.d(TAG, "Failed starting monitor, invalid arguments.");
+ stopSelf();
+ return;
+ }
+ Runnable monitor = new MonitorRunnable(this);
+ tMonitor = new Thread(monitor);
+ tMonitor.start();
+ }
+
+ private void stopService() {
+ stopThread();
+ stopSelf();
+ Log.d(TAG, "SvcMonitor stopped");
+ }
+
+ private void stopThread() {
+ if (tMonitor == null) {
+ Log.d(TAG, "no active thread");
+ return;
+ }
+ Log.d(TAG, "interrupting monitor thread");
+ tMonitor.interrupt();
+ try {
+ tMonitor.join();
+ } catch (InterruptedException e) {
+ Log.d(TAG, "Unable to finish monitor thread");
+ }
+ tMonitor = null;
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ throw new UnsupportedOperationException("Not yet implemented");
+ }
+
+ public static class MonitorRunnable implements Runnable {
+ long java_time_old, hal_time_old, cpu_time_old = -1;
+ String javaPID, halPID;
+ SvcMonitor svcmonitor;
+ static String javaProcTAG;
+ int period;
+
+ public MonitorRunnable(SvcMonitor svcmonitor) {
+ this.svcmonitor = svcmonitor;
+ this.period = svcmonitor.period;
+ javaPID = getPIDof(svcmonitor.javaProc);
+ halPID = getPIDof(svcmonitor.halProc);
+ java_time_old = getPsTime(javaPID);
+ hal_time_old = getPsTime(halPID);
+ cpu_time_old = getPsTime("");
+ javaProcTAG = String.valueOf(svcmonitor.javaProc.toCharArray());
+ }
+
+ @Override
+ public void run() {
+ if (halPID.isEmpty() || javaPID.isEmpty()) {
+ Log.d(javaProcTAG, "No such process: " +
+ (halPID.isEmpty() ? svcmonitor.halProc : svcmonitor.javaProc));
+ return;
+ }
+ while (!Thread.interrupted()) {
+ calculateUsage();
+ SystemClock.sleep(period);
+ }
+ Log.d(TAG, "Stopping monitor thread");
+ }
+
+ private void calculateUsage() {
+ long java_time = getPsTime(javaPID);
+ long hal_time = getPsTime(halPID);
+ long cpu_time = getPsTime("");
+
+ if (cpu_time_old >= 0) {
+ float java_diff = (float) (java_time - java_time_old);
+ float hal_diff = (float) (hal_time - hal_time_old);
+ float cpu_diff = (float) (cpu_time - cpu_time_old);
+ Log.w(javaProcTAG, "\n----------------\n");
+ Log.w(javaProcTAG, "JAVA level CPU: "
+ + (java_diff * 100.0 / cpu_diff) + "%\n");
+ Log.w(javaProcTAG, " HAL level CPU: "
+ + (hal_diff * 100.0 / cpu_diff) + "%\n");
+ Log.w(javaProcTAG, " SYS level CPU: "
+ + ((java_diff + hal_diff) * 100.0 / cpu_diff) + "%\n");
+ } else {
+ Log.w(TAG, "Waiting for status\n");
+ }
+
+ java_time_old = java_time;
+ hal_time_old = hal_time;
+ cpu_time_old = cpu_time;
+ }
+
+ private String getPIDof(String psName) {
+ String pid = "";
+
+ try {
+ String[] cmd = {"/system/bin/sh", "-c", "ps | grep " + psName};
+ Process ps = Runtime.getRuntime().exec(cmd);
+ BufferedReader in = new BufferedReader(
+ new InputStreamReader(ps.getInputStream()));
+ String temp = in.readLine();
+ if (temp == null || temp.isEmpty())
+ throw new IOException("No such process: " + psName);
+ pid = temp.split(" +")[1];
+ in.close();
+ } catch (IOException e) {
+ Log.d(javaProcTAG, "Error finding PID of process: " + psName + "\n", e);
+ }
+ return pid;
+ }
+
+ private long getPsTime(String pid) {
+ String psStat = getPsStat("/" + pid);
+ String[] statBreakDown = psStat.split(" +");
+ long psTime;
+
+ if (pid.isEmpty()) {
+ psTime = Long.parseLong(statBreakDown[1])
+ + Long.parseLong(statBreakDown[2])
+ + Long.parseLong(statBreakDown[3])
+ + Long.parseLong(statBreakDown[4]);
+ } else {
+ psTime = Long.parseLong(statBreakDown[13])
+ + Long.parseLong(statBreakDown[14]);
+ }
+
+ return psTime;
+ }
+
+ private String getPsStat(String psname) {
+ String stat = "";
+ try {
+ FileInputStream fs = new FileInputStream("/proc" + psname + "/stat");
+ BufferedReader br = new BufferedReader(new InputStreamReader(fs));
+ stat = br.readLine();
+ fs.close();
+ } catch (IOException e) {
+ Log.d(TAG, "Error retreiving stat. \n");
+ }
+ return stat;
+ }
+ }
+}
diff --git a/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp b/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp
index e0b616c16184..3e8301038359 100644
--- a/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp
+++ b/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp
@@ -22,7 +22,7 @@ static jint checkFunction(JNIEnv*, jclass) {
return 1;
}
-static JNINativeMethod sMethods[] = {
+static const JNINativeMethod sMethods[] = {
/* name, signature, funcPtr */
{ "checkFunction", "()I", (void*) checkFunction },
};
diff --git a/core/tests/coretests/assets/fonts/HintedAdvanceWidthTest-Regular.ttf b/core/tests/coretests/assets/fonts/HintedAdvanceWidthTest-Regular.ttf
new file mode 100644
index 000000000000..1924c35a9c0a
--- /dev/null
+++ b/core/tests/coretests/assets/fonts/HintedAdvanceWidthTest-Regular.ttf
Binary files differ
diff --git a/core/tests/coretests/assets/fonts/HintedAdvanceWidthTest-Regular.ttx b/core/tests/coretests/assets/fonts/HintedAdvanceWidthTest-Regular.ttx
new file mode 100644
index 000000000000..2b8478d522d2
--- /dev/null
+++ b/core/tests/coretests/assets/fonts/HintedAdvanceWidthTest-Regular.ttx
@@ -0,0 +1,328 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.0">
+
+ <GlyphOrder>
+ <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
+ <GlyphID id="0" name=".notdef"/>
+ <GlyphID id="1" name="space"/>
+ <GlyphID id="9" name="H"/>
+ <GlyphID id="16" name="O"/>
+ </GlyphOrder>
+
+ <head>
+ <!-- Most of this table will be recalculated by the compiler -->
+ <tableVersion value="1.0"/>
+ <fontRevision value="1.0"/>
+ <checkSumAdjustment value="0x640cdb2f"/>
+ <magicNumber value="0x5f0f3cf5"/>
+ <flags value="00000000 00000011"/>
+ <unitsPerEm value="1000"/>
+ <created value="Wed Sep 9 08:01:17 2015"/>
+ <modified value="Wed Sep 9 08:48:07 2015"/>
+ <xMin value="30"/>
+ <yMin value="-200"/>
+ <xMax value="629"/>
+ <yMax value="800"/>
+ <macStyle value="00000000 00000000"/>
+ <lowestRecPPEM value="7"/>
+ <fontDirectionHint value="2"/>
+ <indexToLocFormat value="0"/>
+ <glyphDataFormat value="0"/>
+ </head>
+
+ <hhea>
+ <tableVersion value="1.0"/>
+ <ascent value="1000"/>
+ <descent value="-200"/>
+ <lineGap value="0"/>
+ <advanceWidthMax value="659"/>
+ <minLeftSideBearing value="0"/>
+ <minRightSideBearing value="30"/>
+ <xMaxExtent value="629"/>
+ <caretSlopeRise value="1"/>
+ <caretSlopeRun value="0"/>
+ <caretOffset value="0"/>
+ <reserved0 value="0"/>
+ <reserved1 value="0"/>
+ <reserved2 value="0"/>
+ <reserved3 value="0"/>
+ <metricDataFormat value="0"/>
+ <numberOfHMetrics value="18"/>
+ </hhea>
+
+ <maxp>
+ <!-- Most of this table will be recalculated by the compiler -->
+ <tableVersion value="0x10000"/>
+ <numGlyphs value="54"/>
+ <maxPoints value="73"/>
+ <maxContours value="10"/>
+ <maxCompositePoints value="0"/>
+ <maxCompositeContours value="0"/>
+ <maxZones value="2"/>
+ <maxTwilightPoints value="12"/>
+ <maxStorage value="28"/>
+ <maxFunctionDefs value="119"/>
+ <maxInstructionDefs value="0"/>
+ <maxStackElements value="61"/>
+ <maxSizeOfInstructions value="2967"/>
+ <maxComponentElements value="0"/>
+ <maxComponentDepth value="0"/>
+ </maxp>
+
+ <OS_2>
+ <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
+ will be recalculated by the compiler -->
+ <version value="3"/>
+ <xAvgCharWidth value="594"/>
+ <usWeightClass value="400"/>
+ <usWidthClass value="5"/>
+ <fsType value="00000000 00001000"/>
+ <ySubscriptXSize value="650"/>
+ <ySubscriptYSize value="600"/>
+ <ySubscriptXOffset value="0"/>
+ <ySubscriptYOffset value="75"/>
+ <ySuperscriptXSize value="650"/>
+ <ySuperscriptYSize value="600"/>
+ <ySuperscriptXOffset value="0"/>
+ <ySuperscriptYOffset value="350"/>
+ <yStrikeoutSize value="50"/>
+ <yStrikeoutPosition value="300"/>
+ <sFamilyClass value="0"/>
+ <panose>
+ <bFamilyType value="0"/>
+ <bSerifStyle value="0"/>
+ <bWeight value="5"/>
+ <bProportion value="0"/>
+ <bContrast value="0"/>
+ <bStrokeVariation value="0"/>
+ <bArmStyle value="0"/>
+ <bLetterForm value="0"/>
+ <bMidline value="0"/>
+ <bXHeight value="0"/>
+ </panose>
+ <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
+ <achVendID value="UKWN"/>
+ <fsSelection value="00000000 01000000"/>
+ <usFirstCharIndex value="32"/>
+ <usLastCharIndex value="122"/>
+ <sTypoAscender value="800"/>
+ <sTypoDescender value="-200"/>
+ <sTypoLineGap value="200"/>
+ <usWinAscent value="1000"/>
+ <usWinDescent value="200"/>
+ <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
+ <sxHeight value="500"/>
+ <sCapHeight value="700"/>
+ <usDefaultChar value="0"/>
+ <usBreakChar value="32"/>
+ <usMaxContext value="0"/>
+ </OS_2>
+
+ <hmtx>
+ <mtx name=".notdef" width="500" lsb="93"/>
+ <mtx name="H" width="627" lsb="50"/>
+ <mtx name="O" width="659" lsb="30"/>
+ <mtx name="space" width="300" lsb="0"/>
+ </hmtx>
+
+ <cmap>
+ <tableVersion version="0"/>
+ <cmap_format_4 platformID="0" platEncID="3" language="0">
+ <map code="0x20" name="space"/><!-- SPACE -->
+ <map code="0x48" name="H"/><!-- LATIN CAPITAL LETTER H -->
+ <map code="0x4f" name="O"/><!-- LATIN CAPITAL LETTER O -->
+ </cmap_format_4>
+ <cmap_format_4 platformID="3" platEncID="1" language="0">
+ <map code="0x20" name="space"/><!-- SPACE -->
+ <map code="0x48" name="H"/><!-- LATIN CAPITAL LETTER H -->
+ <map code="0x4f" name="O"/><!-- LATIN CAPITAL LETTER O -->
+ </cmap_format_4>
+ </cmap>
+
+ <fpgm>
+ <assembly>
+ </assembly>
+ </fpgm>
+
+ <prep>
+ <assembly>
+ </assembly>
+ </prep>
+
+ <cvt>
+ <cv index="0" value="0"/>
+ </cvt>
+
+ <loca>
+ <!-- The 'loca' table will be calculated by the compiler -->
+ </loca>
+
+ <glyf>
+
+ <!-- The xMin, yMin, xMax and yMax values
+ will be recalculated by the compiler. -->
+
+ <TTGlyph name=".notdef" xMin="93" yMin="-200" xMax="410" yMax="800">
+ <contour>
+ <pt x="410" y="0" on="1"/>
+ <pt x="50" y="0" on="1"/>
+ <pt x="50" y="700" on="1"/>
+ <pt x="410" y="700" on="1"/>
+ </contour>
+ <instructions><assembly>
+ PUSHB[] 1 2 4 3
+ SLOOP[]
+ PUSH[] -400
+ SHPIX[]
+
+ PUSHB[] 0 3 5 3
+ SLOOP[]
+ PUSH[] 400
+ SHPIX[]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="H" xMin="50" yMin="0" xMax="577" yMax="700">
+ <contour>
+ <pt x="50" y="700" on="1"/>
+ <pt x="200" y="700" on="1"/>
+ <pt x="200" y="447" on="1"/>
+ <pt x="427" y="447" on="1"/>
+ <pt x="427" y="700" on="1"/>
+ <pt x="577" y="700" on="1"/>
+ <pt x="577" y="0" on="1"/>
+ <pt x="427" y="0" on="1"/>
+ <pt x="427" y="297" on="1"/>
+ <pt x="200" y="297" on="1"/>
+ <pt x="200" y="0" on="1"/>
+ <pt x="50" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ PUSHB[] 0 11 12 3
+ SLOOP[]
+ PUSH[] -200
+ SHPIX[]
+ PUSHB[] 5 6 13 3
+ SLOOP[]
+ PUSH[] 200
+ SHPIX[]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="O" xMin="30" yMin="0" xMax="629" yMax="700">
+ <contour>
+ <pt x="248" y="0" on="0"/>
+ <pt x="111" y="94" on="0"/>
+ <pt x="30" y="255" on="0"/>
+ <pt x="30" y="350" on="1"/>
+ <pt x="30" y="445" on="0"/>
+ <pt x="111" y="606" on="0"/>
+ <pt x="248" y="700" on="0"/>
+ <pt x="330" y="700" on="1"/>
+ <pt x="411" y="700" on="0"/>
+ <pt x="548" y="606" on="0"/>
+ <pt x="629" y="445" on="0"/>
+ <pt x="629" y="350" on="1"/>
+ <pt x="629" y="255" on="0"/>
+ <pt x="548" y="94" on="0"/>
+ <pt x="411" y="0" on="0"/>
+ <pt x="330" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="370" y="150" on="0"/>
+ <pt x="439" y="209" on="0"/>
+ <pt x="480" y="302" on="0"/>
+ <pt x="480" y="350" on="1"/>
+ <pt x="480" y="398" on="0"/>
+ <pt x="439" y="491" on="0"/>
+ <pt x="370" y="550" on="0"/>
+ <pt x="330" y="550" on="1"/>
+ <pt x="289" y="550" on="0"/>
+ <pt x="220" y="491" on="0"/>
+ <pt x="179" y="398" on="0"/>
+ <pt x="179" y="350" on="1"/>
+ <pt x="179" y="302" on="0"/>
+ <pt x="220" y="209" on="0"/>
+ <pt x="289" y="150" on="0"/>
+ <pt x="330" y="150" on="1"/>
+ </contour>
+ <instructions><assembly>
+ PUSH[] 32 -200
+ SHPIX[]
+ PUSHB[] 33 200
+ SHPIX[]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="space">
+ <contour></contour>
+ <instructions><assembly>
+ PUSH[] 0 -200
+ SHPIX[]
+ PUSHB[] 1 200
+ SHPIX[]
+ </assembly></instructions>
+ </TTGlyph>
+
+ </glyf>
+
+ <name>
+ <namerecord nameID="1" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ Hinted Advance Width Test
+ </namerecord>
+ <namerecord nameID="2" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ Regular
+ </namerecord>
+ <namerecord nameID="4" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ Hinted Advance Width Test
+ </namerecord>
+ <namerecord nameID="6" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ HintedAdvanceWidthTest-Regular
+ </namerecord>
+ <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
+ Hinted Advance Width Test
+ </namerecord>
+ <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
+ Regular
+ </namerecord>
+ <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
+ Hinted Advance Width Test
+ </namerecord>
+ <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
+ HintedAdvanceWidthTest-Regular
+ </namerecord>
+ </name>
+
+ <post>
+ <formatType value="2.0"/>
+ <italicAngle value="0.0"/>
+ <underlinePosition value="-75"/>
+ <underlineThickness value="50"/>
+ <isFixedPitch value="0"/>
+ <minMemType42 value="0"/>
+ <maxMemType42 value="0"/>
+ <minMemType1 value="0"/>
+ <maxMemType1 value="0"/>
+ <psNames>
+ <!-- This file uses unique glyph names based on the information
+ found in the 'post' table. Since these names might not be unique,
+ we have to invent artificial names in case of clashes. In order to
+ be able to retain the original information, we need a name to
+ ps name mapping for those cases where they differ. That's what
+ you see below.
+ -->
+ </psNames>
+ <extraNames>
+ <!-- following are the name that are not taken from the standard Mac glyph order -->
+ </extraNames>
+ </post>
+
+ <gasp>
+ <gaspRange rangeMaxPPEM="65535" rangeGaspBehavior="15"/>
+ </gasp>
+
+</ttFont>
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index 0fee6c394e50..9498f4c81d12 100644
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -1168,16 +1168,10 @@ public class PackageManagerTests extends AndroidTestCase {
}
boolean checkMediaState(String desired) {
- try {
- String mPath = Environment.getExternalStorageDirectory().getPath();
- String actual = getMs().getVolumeState(mPath);
- if (desired.equals(actual)) {
- return true;
- } else {
- return false;
- }
- } catch (RemoteException e) {
- Log.e(TAG, "Exception while checking media state", e);
+ String actual = Environment.getExternalStorageState();
+ if (desired.equals(actual)) {
+ return true;
+ } else {
return false;
}
}
diff --git a/core/tests/coretests/src/android/graphics/PaintTest.java b/core/tests/coretests/src/android/graphics/PaintTest.java
new file mode 100644
index 000000000000..e97bb33487c4
--- /dev/null
+++ b/core/tests/coretests/src/android/graphics/PaintTest.java
@@ -0,0 +1,97 @@
+/*
+ * 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.graphics.Paint;
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * PaintTest tests {@link Paint}.
+ */
+public class PaintTest extends InstrumentationTestCase {
+ private static final String FONT_PATH = "fonts/HintedAdvanceWidthTest-Regular.ttf";
+
+ static void assertEquals(String message, float[] expected, float[] actual) {
+ if (expected.length != actual.length) {
+ fail(message + " expected array length:<" + expected.length + "> but was:<"
+ + actual.length + ">");
+ }
+ for (int i = 0; i < expected.length; ++i) {
+ if (expected[i] != actual[i]) {
+ fail(message + " expected array element[" +i + "]:<" + expected[i] + ">but was:<"
+ + actual[i] + ">");
+ }
+ }
+ }
+
+ static class HintingTestCase {
+ public final String mText;
+ public final float mTextSize;
+ public final float[] mWidthWithoutHinting;
+ public final float[] mWidthWithHinting;
+
+ public HintingTestCase(String text, float textSize, float[] widthWithoutHinting,
+ float[] widthWithHinting) {
+ mText = text;
+ mTextSize = textSize;
+ mWidthWithoutHinting = widthWithoutHinting;
+ mWidthWithHinting = widthWithHinting;
+ }
+ }
+
+ // Following test cases are only valid for HintedAdvanceWidthTest-Regular.ttf in assets/fonts.
+ HintingTestCase[] HINTING_TESTCASES = {
+ new HintingTestCase("H", 11f, new float[] { 7f }, new float[] { 13f }),
+ new HintingTestCase("O", 11f, new float[] { 7f }, new float[] { 13f }),
+
+ new HintingTestCase("H", 13f, new float[] { 8f }, new float[] { 14f }),
+ new HintingTestCase("O", 13f, new float[] { 9f }, new float[] { 15f }),
+
+ new HintingTestCase("HO", 11f, new float[] { 7f, 7f }, new float[] { 13f, 13f }),
+ new HintingTestCase("OH", 11f, new float[] { 7f, 7f }, new float[] { 13f, 13f }),
+
+ new HintingTestCase("HO", 13f, new float[] { 8f, 9f }, new float[] { 14f, 15f }),
+ new HintingTestCase("OH", 13f, new float[] { 9f, 8f }, new float[] { 15f, 14f }),
+ };
+
+ @SmallTest
+ public void testHintingWidth() {
+ final Typeface fontTypeface = Typeface.createFromAsset(
+ getInstrumentation().getContext().getAssets(), FONT_PATH);
+ Paint paint = new Paint();
+ paint.setTypeface(fontTypeface);
+
+ for (int i = 0; i < HINTING_TESTCASES.length; ++i) {
+ HintingTestCase testCase = HINTING_TESTCASES[i];
+
+ paint.setTextSize(testCase.mTextSize);
+
+ float[] widths = new float[testCase.mText.length()];
+
+ paint.setHinting(Paint.HINTING_OFF);
+ paint.getTextWidths(String.valueOf(testCase.mText), widths);
+ assertEquals("Text width of '" + testCase.mText + "' without hinting is not expected.",
+ testCase.mWidthWithoutHinting, widths);
+
+ paint.setHinting(Paint.HINTING_ON);
+ paint.getTextWidths(String.valueOf(testCase.mText), widths);
+ assertEquals("Text width of '" + testCase.mText + "' with hinting is not expected.",
+ testCase.mWidthWithHinting, widths);
+ }
+ }
+}
diff --git a/core/tests/coretests/src/android/text/method/WordIteratorTest.java b/core/tests/coretests/src/android/text/method/WordIteratorTest.java
new file mode 100644
index 000000000000..37f887cd310e
--- /dev/null
+++ b/core/tests/coretests/src/android/text/method/WordIteratorTest.java
@@ -0,0 +1,458 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.text.method;
+
+import android.test.AndroidTestCase;
+
+import java.text.BreakIterator;
+import java.util.Locale;
+
+// TODO(Bug: 24062099): Add more tests for non-ascii text.
+public class WordIteratorTest extends AndroidTestCase {
+
+ public void testSetCharSequence() {
+ final String text = "text";
+ WordIterator wordIterator = new WordIterator(Locale.ENGLISH);
+
+ try {
+ wordIterator.setCharSequence(text, 100, 100);
+ fail("setCharSequence with invalid start and end values should throw "
+ + "IndexOutOfBoundsException.");
+ } catch (IndexOutOfBoundsException e) {
+ }
+ try {
+ wordIterator.setCharSequence(text, -100, -100);
+ fail("setCharSequence with invalid start and end values should throw "
+ + "IndexOutOfBoundsException.");
+ } catch (IndexOutOfBoundsException e) {
+ }
+
+ wordIterator.setCharSequence(text, 0, text.length());
+ wordIterator.setCharSequence(text, 0, 0);
+ wordIterator.setCharSequence(text, text.length(), text.length());
+ }
+
+ public void testPreceding() {
+ final String text = "abc def-ghi. jkl";
+ WordIterator wordIterator = new WordIterator(Locale.ENGLISH);
+ wordIterator.setCharSequence(text, 0, text.length());
+
+ try {
+ wordIterator.preceding(-1);
+ fail("preceding with invalid offset should throw IllegalArgumentException.");
+ } catch (IllegalArgumentException e) {
+ }
+ try {
+ wordIterator.preceding(text.length() + 1);
+ fail("preceding with invalid offset should throw IllegalArgumentException.");
+ } catch (IllegalArgumentException e) {
+ }
+
+ assertEquals(BreakIterator.DONE, wordIterator.preceding(text.indexOf('a')));
+ assertEquals(text.indexOf('a'), wordIterator.preceding(text.indexOf('c')));
+ assertEquals(text.indexOf('a'), wordIterator.preceding(text.indexOf('d')));
+ assertEquals(text.indexOf('d'), wordIterator.preceding(text.indexOf('e')));
+ assertEquals(text.indexOf('d'), wordIterator.preceding(text.indexOf('g')));
+ assertEquals(text.indexOf('g'), wordIterator.preceding(text.indexOf('h')));
+ assertEquals(text.indexOf('g'), wordIterator.preceding(text.indexOf('j')));
+ assertEquals(text.indexOf('j'), wordIterator.preceding(text.indexOf('l')));
+ }
+
+ public void testFollowing() {
+ final String text = "abc def-ghi. jkl";
+ WordIterator wordIterator = new WordIterator(Locale.ENGLISH);
+ wordIterator.setCharSequence(text, 0, text.length());
+
+ try {
+ wordIterator.following(-1);
+ fail("following with invalid offset should throw IllegalArgumentException.");
+ } catch (IllegalArgumentException e) {
+ }
+ try {
+ wordIterator.following(text.length() + 1);
+ fail("following with invalid offset should throw IllegalArgumentException.");
+ } catch (IllegalArgumentException e) {
+ }
+
+ assertEquals(text.indexOf('c') + 1, wordIterator.following(text.indexOf('a')));
+ assertEquals(text.indexOf('c') + 1, wordIterator.following(text.indexOf('c')));
+ assertEquals(text.indexOf('f') + 1, wordIterator.following(text.indexOf('c') + 1));
+ assertEquals(text.indexOf('f') + 1, wordIterator.following(text.indexOf('d')));
+ assertEquals(text.indexOf('i') + 1, wordIterator.following(text.indexOf('-')));
+ assertEquals(text.indexOf('i') + 1, wordIterator.following(text.indexOf('g')));
+ assertEquals(text.length(), wordIterator.following(text.indexOf('j')));
+ assertEquals(BreakIterator.DONE, wordIterator.following(text.length()));
+ }
+
+ public void testIsBoundary() {
+ final String text = "abc def-ghi. jkl";
+ WordIterator wordIterator = new WordIterator(Locale.ENGLISH);
+ wordIterator.setCharSequence(text, 0, text.length());
+
+ try {
+ wordIterator.isBoundary(-1);
+ fail("isBoundary with invalid offset should throw IllegalArgumentException.");
+ } catch (IllegalArgumentException e) {
+ }
+ try {
+ wordIterator.isBoundary(text.length() + 1);
+ fail("isBoundary with invalid offset should throw IllegalArgumentException.");
+ } catch (IllegalArgumentException e) {
+ }
+
+ assertTrue(wordIterator.isBoundary(text.indexOf('a')));
+ assertFalse(wordIterator.isBoundary(text.indexOf('b')));
+ assertTrue(wordIterator.isBoundary(text.indexOf('c') + 1));
+ assertTrue(wordIterator.isBoundary(text.indexOf('d')));
+ assertTrue(wordIterator.isBoundary(text.indexOf('-')));
+ assertTrue(wordIterator.isBoundary(text.indexOf('g')));
+ assertTrue(wordIterator.isBoundary(text.indexOf('.')));
+ assertTrue(wordIterator.isBoundary(text.indexOf('j')));
+ assertTrue(wordIterator.isBoundary(text.length()));
+ }
+
+ public void testNextBoundary() {
+ final String text = "abc def-ghi. jkl";
+ WordIterator wordIterator = new WordIterator(Locale.ENGLISH);
+ wordIterator.setCharSequence(text, 0, text.length());
+
+ try {
+ wordIterator.nextBoundary(-1);
+ fail("nextBoundary with invalid offset should throw IllegalArgumentException.");
+ } catch (IllegalArgumentException e) {
+ }
+ try {
+ wordIterator.nextBoundary(text.length() + 1);
+ fail("nextBoundary with invalid offset should throw IllegalArgumentException.");
+ } catch (IllegalArgumentException e) {
+ }
+
+
+ int currentOffset = 0;
+ currentOffset = wordIterator.nextBoundary(currentOffset);
+ assertEquals(text.indexOf('c') + 1, currentOffset);
+
+ currentOffset = wordIterator.nextBoundary(currentOffset);
+ assertEquals(text.indexOf('d'), currentOffset);
+
+ currentOffset = wordIterator.nextBoundary(currentOffset);
+ assertEquals(text.indexOf('f') + 1, currentOffset);
+
+ currentOffset = wordIterator.nextBoundary(currentOffset);
+ assertEquals(text.indexOf('g'), currentOffset);
+
+ currentOffset = wordIterator.nextBoundary(currentOffset);
+ assertEquals(text.indexOf('i') + 1, currentOffset);
+
+ currentOffset = wordIterator.nextBoundary(currentOffset);
+ assertEquals(text.indexOf('.') + 1, currentOffset);
+
+ currentOffset = wordIterator.nextBoundary(currentOffset);
+ assertEquals(text.indexOf('j'), currentOffset);
+
+ currentOffset = wordIterator.nextBoundary(currentOffset);
+ assertEquals(text.length(), currentOffset);
+
+ currentOffset = wordIterator.nextBoundary(currentOffset);
+ assertEquals(BreakIterator.DONE, currentOffset);
+ }
+
+ public void testPrevBoundary() {
+ final String text = "abc def-ghi. jkl";
+ WordIterator wordIterator = new WordIterator(Locale.ENGLISH);
+ wordIterator.setCharSequence(text, 0, text.length());
+
+ try {
+ wordIterator.prevBoundary(-1);
+ fail("prevBoundary with invalid offset should throw IllegalArgumentException.");
+ } catch (IllegalArgumentException e) {
+ }
+ try {
+ wordIterator.prevBoundary(text.length() + 1);
+ fail("prevBoundary with invalid offset should throw IllegalArgumentException.");
+ } catch (IllegalArgumentException e) {
+ }
+
+ int currentOffset = text.length();
+ currentOffset = wordIterator.prevBoundary(currentOffset);
+ assertEquals(text.indexOf('j'), currentOffset);
+
+ currentOffset = wordIterator.prevBoundary(currentOffset);
+ assertEquals(text.indexOf('.') + 1, currentOffset);
+
+ currentOffset = wordIterator.prevBoundary(currentOffset);
+ assertEquals(text.indexOf('i') + 1, currentOffset);
+
+ currentOffset = wordIterator.prevBoundary(currentOffset);
+ assertEquals(text.indexOf('g'), currentOffset);
+
+ currentOffset = wordIterator.prevBoundary(currentOffset);
+ assertEquals(text.indexOf('f') + 1, currentOffset);
+
+ currentOffset = wordIterator.prevBoundary(currentOffset);
+ assertEquals(text.indexOf('d'), currentOffset);
+
+ currentOffset = wordIterator.prevBoundary(currentOffset);
+ assertEquals(text.indexOf('c') + 1, currentOffset);
+
+ currentOffset = wordIterator.prevBoundary(currentOffset);
+ assertEquals(text.indexOf('a'), currentOffset);
+
+ currentOffset = wordIterator.prevBoundary(currentOffset);
+ assertEquals(BreakIterator.DONE, currentOffset);
+ }
+
+ public void testGetBeginning() {
+ {
+ final String text = "abc def-ghi. jkl";
+ WordIterator wordIterator = new WordIterator(Locale.ENGLISH);
+ wordIterator.setCharSequence(text, 0, text.length());
+ try {
+ wordIterator.getBeginning(-1);
+ fail("getBeginning with invalid offset should throw IllegalArgumentException.");
+ } catch (IllegalArgumentException e) {
+ }
+ try {
+ wordIterator.getBeginning(text.length() + 1);
+ fail("getBeginning with invalid offset should throw IllegalArgumentException.");
+ } catch (IllegalArgumentException e) {
+ }
+ try {
+ wordIterator.getPrevWordBeginningOnTwoWordsBoundary(-1);
+ fail("getPrevWordBeginningOnTwoWordsBoundary with invalid offset should throw "
+ + "IllegalArgumentException.");
+ } catch (IllegalArgumentException e) {
+ }
+ try {
+ wordIterator.getPrevWordBeginningOnTwoWordsBoundary(text.length() + 1);
+ fail("getPrevWordBeginningOnTwoWordsBoundary with invalid offset should throw "
+ + "IllegalArgumentException.");
+ } catch (IllegalArgumentException e) {
+ }
+ }
+
+ {
+ final String text = "abc def-ghi. jkl";
+ WordIterator wordIterator = new WordIterator(Locale.ENGLISH);
+ wordIterator.setCharSequence(text, 0, text.length());
+
+ assertEquals(text.indexOf('a'), wordIterator.getBeginning(text.indexOf('a')));
+ assertEquals(text.indexOf('a'), wordIterator.getBeginning(text.indexOf('c')));
+ assertEquals(text.indexOf('a'), wordIterator.getBeginning(text.indexOf('c') + 1));
+ assertEquals(text.indexOf('d'), wordIterator.getBeginning(text.indexOf('d')));
+ assertEquals(text.indexOf('d'), wordIterator.getBeginning(text.indexOf('-')));
+ assertEquals(text.indexOf('g'), wordIterator.getBeginning(text.indexOf('g')));
+ assertEquals(text.indexOf('g'), wordIterator.getBeginning(text.indexOf('.')));
+ assertEquals(BreakIterator.DONE, wordIterator.getBeginning(text.indexOf('.') + 1));
+ assertEquals(text.indexOf('j'), wordIterator.getBeginning(text.indexOf('j')));
+ assertEquals(text.indexOf('j'), wordIterator.getBeginning(text.indexOf('l') + 1));
+
+ for (int i = 0; i < text.length(); i++) {
+ assertEquals(wordIterator.getBeginning(i),
+ wordIterator.getPrevWordBeginningOnTwoWordsBoundary(i));
+ }
+ }
+
+ {
+ // Japanese HIRAGANA letter + KATAKANA letters
+ final String text = "\u3042\u30A2\u30A3\u30A4";
+ WordIterator wordIterator = new WordIterator(Locale.JAPANESE);
+ wordIterator.setCharSequence(text, 0, text.length());
+
+ assertEquals(text.indexOf('\u3042'), wordIterator.getBeginning(text.indexOf('\u3042')));
+ assertEquals(text.indexOf('\u30A2'), wordIterator.getBeginning(text.indexOf('\u30A2')));
+ assertEquals(text.indexOf('\u30A2'), wordIterator.getBeginning(text.indexOf('\u30A4')));
+ assertEquals(text.indexOf('\u30A2'), wordIterator.getBeginning(text.length()));
+
+ assertEquals(text.indexOf('\u3042'),
+ wordIterator.getPrevWordBeginningOnTwoWordsBoundary(text.indexOf('\u3042')));
+ assertEquals(text.indexOf('\u3042'),
+ wordIterator.getPrevWordBeginningOnTwoWordsBoundary(text.indexOf('\u30A2')));
+ assertEquals(text.indexOf('\u30A2'),
+ wordIterator.getPrevWordBeginningOnTwoWordsBoundary(text.indexOf('\u30A4')));
+ assertEquals(text.indexOf('\u30A2'),
+ wordIterator.getPrevWordBeginningOnTwoWordsBoundary(text.length()));
+ }
+ }
+
+ public void testGetEnd() {
+ {
+ final String text = "abc def-ghi. jkl";
+ WordIterator wordIterator = new WordIterator(Locale.ENGLISH);
+ wordIterator.setCharSequence(text, 0, text.length());
+ try {
+ wordIterator.getEnd(-1);
+ fail("getEnd with invalid offset should throw IllegalArgumentException.");
+ } catch (IllegalArgumentException e) {
+ }
+ try {
+ wordIterator.getEnd(text.length() + 1);
+ fail("getEnd with invalid offset should throw IllegalArgumentException.");
+ } catch (IllegalArgumentException e) {
+ }
+ try {
+ wordIterator.getNextWordEndOnTwoWordBoundary(-1);
+ fail("getNextWordEndOnTwoWordBoundary with invalid offset should throw "
+ + "IllegalArgumentException.");
+ } catch (IllegalArgumentException e) {
+ }
+ try {
+ wordIterator.getNextWordEndOnTwoWordBoundary(text.length() + 1);
+ fail("getNextWordEndOnTwoWordBoundary with invalid offset should throw "
+ + "IllegalArgumentException.");
+ } catch (IllegalArgumentException e) {
+ }
+ }
+
+ {
+ final String text = "abc def-ghi. jkl";
+ WordIterator wordIterator = new WordIterator(Locale.ENGLISH);
+ wordIterator.setCharSequence(text, 0, text.length());
+
+ assertEquals(text.indexOf('c') + 1, wordIterator.getEnd(text.indexOf('a')));
+ assertEquals(text.indexOf('c') + 1, wordIterator.getEnd(text.indexOf('c')));
+ assertEquals(text.indexOf('c') + 1, wordIterator.getEnd(text.indexOf('c') + 1));
+ assertEquals(text.indexOf('f') + 1, wordIterator.getEnd(text.indexOf('d')));
+ assertEquals(text.indexOf('f') + 1, wordIterator.getEnd(text.indexOf('f') + 1));
+ assertEquals(text.indexOf('i') + 1, wordIterator.getEnd(text.indexOf('g')));
+ assertEquals(text.indexOf('i') + 1, wordIterator.getEnd(text.indexOf('i') + 1));
+ assertEquals(BreakIterator.DONE, wordIterator.getEnd(text.indexOf('.') + 1));
+ assertEquals(text.indexOf('l') + 1, wordIterator.getEnd(text.indexOf('j')));
+ assertEquals(text.indexOf('l') + 1, wordIterator.getEnd(text.indexOf('l') + 1));
+
+ for (int i = 0; i < text.length(); i++) {
+ assertEquals(wordIterator.getEnd(i),
+ wordIterator.getNextWordEndOnTwoWordBoundary(i));
+ }
+ }
+
+ {
+ // Japanese HIRAGANA letter + KATAKANA letters
+ final String text = "\u3042\u30A2\u30A3\u30A4";
+ WordIterator wordIterator = new WordIterator(Locale.JAPANESE);
+ wordIterator.setCharSequence(text, 0, text.length());
+
+ assertEquals(text.indexOf('\u3042') + 1, wordIterator.getEnd(text.indexOf('\u3042')));
+ assertEquals(text.indexOf('\u3042') + 1, wordIterator.getEnd(text.indexOf('\u30A2')));
+ assertEquals(text.indexOf('\u30A4') + 1, wordIterator.getEnd(text.indexOf('\u30A4')));
+ assertEquals(text.indexOf('\u30A4') + 1,
+ wordIterator.getEnd(text.indexOf('\u30A4') + 1));
+
+ assertEquals(text.indexOf('\u3042') + 1,
+ wordIterator.getNextWordEndOnTwoWordBoundary(text.indexOf('\u3042')));
+ assertEquals(text.indexOf('\u30A4') + 1,
+ wordIterator.getNextWordEndOnTwoWordBoundary(text.indexOf('\u30A2')));
+ assertEquals(text.indexOf('\u30A4') + 1,
+ wordIterator.getNextWordEndOnTwoWordBoundary(text.indexOf('\u30A4')));
+ assertEquals(text.indexOf('\u30A4') + 1,
+ wordIterator.getNextWordEndOnTwoWordBoundary(text.indexOf('\u30A4') + 1));
+ }
+ }
+
+ public void testGetPunctuationBeginning() {
+ final String text = "abc!? (^^;) def";
+ WordIterator wordIterator = new WordIterator(Locale.ENGLISH);
+ wordIterator.setCharSequence(text, 0, text.length());
+
+ // TODO: Shouldn't this throw an exception?
+ assertEquals(BreakIterator.DONE, wordIterator.getPunctuationBeginning(BreakIterator.DONE));
+
+ try {
+ wordIterator.getPunctuationBeginning(-2);
+ fail("getPunctuationBeginning with invalid offset should throw "
+ + "IllegalArgumentException.");
+ } catch (IllegalArgumentException e) {
+ }
+ try {
+ wordIterator.getPunctuationBeginning(text.length() + 1);
+ fail("getPunctuationBeginning with invalid offset should throw "
+ + "IllegalArgumentException.");
+ } catch (IllegalArgumentException e) {
+ }
+
+ assertEquals(BreakIterator.DONE, wordIterator.getPunctuationBeginning(text.indexOf('a')));
+ assertEquals(BreakIterator.DONE, wordIterator.getPunctuationBeginning(text.indexOf('c')));
+ assertEquals(text.indexOf('!'), wordIterator.getPunctuationBeginning(text.indexOf('!')));
+ assertEquals(text.indexOf('!'),
+ wordIterator.getPunctuationBeginning(text.indexOf('?') + 1));
+ assertEquals(text.indexOf(';'), wordIterator.getPunctuationBeginning(text.indexOf(';')));
+ assertEquals(text.indexOf(';'), wordIterator.getPunctuationBeginning(text.indexOf(')')));
+ assertEquals(text.indexOf(';'), wordIterator.getPunctuationBeginning(text.length()));
+ }
+
+ public void testGetPunctuationEnd() {
+ final String text = "abc!? (^^;) def";
+ WordIterator wordIterator = new WordIterator(Locale.ENGLISH);
+ wordIterator.setCharSequence(text, 0, text.length());
+
+ // TODO: Shouldn't this throw an exception?
+ assertEquals(BreakIterator.DONE, wordIterator.getPunctuationEnd(BreakIterator.DONE));
+
+ try {
+ wordIterator.getPunctuationEnd(-2);
+ fail("getPunctuationEnd with invalid offset should throw IllegalArgumentException.");
+ } catch (IllegalArgumentException e) {
+ }
+ try {
+ wordIterator.getPunctuationEnd(text.length() + 1);
+ fail("getPunctuationBeginning with invalid offset should throw "
+ + "IllegalArgumentException.");
+ } catch (IllegalArgumentException e) {
+ }
+
+ assertEquals(text.indexOf('?') + 1, wordIterator.getPunctuationEnd(text.indexOf('a')));
+ assertEquals(text.indexOf('?') + 1, wordIterator.getPunctuationEnd(text.indexOf('?') + 1));
+ assertEquals(text.indexOf('(') + 1, wordIterator.getPunctuationEnd(text.indexOf('(')));
+ assertEquals(text.indexOf(')') + 1, wordIterator.getPunctuationEnd(text.indexOf('(') + 2));
+ assertEquals(text.indexOf(')') + 1, wordIterator.getPunctuationEnd(text.indexOf(')') + 1));
+ assertEquals(BreakIterator.DONE, wordIterator.getPunctuationEnd(text.indexOf('d')));
+ assertEquals(BreakIterator.DONE, wordIterator.getPunctuationEnd(text.length()));
+ }
+
+ public void testIsAfterPunctuation() {
+ final String text = "abc!? (^^;) def";
+ WordIterator wordIterator = new WordIterator(Locale.ENGLISH);
+ wordIterator.setCharSequence(text, 0, text.length());
+
+ assertFalse(wordIterator.isAfterPunctuation(text.indexOf('a')));
+ assertFalse(wordIterator.isAfterPunctuation(text.indexOf('!')));
+ assertTrue(wordIterator.isAfterPunctuation(text.indexOf('?')));
+ assertTrue(wordIterator.isAfterPunctuation(text.indexOf('?') + 1));
+ assertFalse(wordIterator.isAfterPunctuation(text.indexOf('d')));
+
+ assertFalse(wordIterator.isAfterPunctuation(BreakIterator.DONE));
+ assertFalse(wordIterator.isAfterPunctuation(text.length() + 1));
+ }
+
+ public void testIsOnPunctuation() {
+ final String text = "abc!? (^^;) def";
+ WordIterator wordIterator = new WordIterator(Locale.ENGLISH);
+ wordIterator.setCharSequence(text, 0, text.length());
+
+ assertFalse(wordIterator.isOnPunctuation(text.indexOf('a')));
+ assertTrue(wordIterator.isOnPunctuation(text.indexOf('!')));
+ assertTrue(wordIterator.isOnPunctuation(text.indexOf('?')));
+ assertFalse(wordIterator.isOnPunctuation(text.indexOf('?') + 1));
+ assertTrue(wordIterator.isOnPunctuation(text.indexOf(')')));
+ assertFalse(wordIterator.isOnPunctuation(text.indexOf(')') + 1));
+ assertFalse(wordIterator.isOnPunctuation(text.indexOf('d')));
+
+ assertFalse(wordIterator.isOnPunctuation(BreakIterator.DONE));
+ assertFalse(wordIterator.isOnPunctuation(text.length()));
+ assertFalse(wordIterator.isOnPunctuation(text.length() + 1));
+ }
+}
diff --git a/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java b/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java
index e5d55425afbd..87b37854a596 100644
--- a/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java
+++ b/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java
@@ -38,15 +38,22 @@ public class SuggestionsPopupWindowTest extends ActivityInstrumentationTestCase2
}
@SmallTest
- public void testTextAndAppearanceInSuggestionsPopup() {
+ public void testTextAppearanceInSuggestionsPopup() {
final Activity activity = getActivity();
final String sampleText = "abc def ghi";
- final String[] candidate = {"DEF", "Def"};
- final SuggestionSpan suggestionSpan = new SuggestionSpan(activity, candidate,
- SuggestionSpan.FLAG_AUTO_CORRECTION);
- final int spanStart = 4;
- final int spanEnd = 7;
+ final String[] singleWordCandidates = {"DEF", "Def"};
+ final SuggestionSpan singleWordSuggestionSpan = new SuggestionSpan(activity,
+ singleWordCandidates, SuggestionSpan.FLAG_AUTO_CORRECTION);
+ final int singleWordSpanStart = 4;
+ final int singleWordSpanEnd = 7;
+
+ final String[] multiWordCandidates = {"ABC DEF GHI", "Abc Def Ghi"};
+ final SuggestionSpan multiWordSuggestionSpan = new SuggestionSpan(activity,
+ multiWordCandidates, SuggestionSpan.FLAG_AUTO_CORRECTION);
+ final int multiWordSpanStart = 0;
+ final int multiWordSpanEnd = 11;
+
TextAppearanceSpan expectedSpan = new TextAppearanceSpan(activity,
android.R.style.TextAppearance_SuggestionHighlight);
TextPaint tmpTp = new TextPaint();
@@ -62,22 +69,27 @@ public class SuggestionsPopupWindowTest extends ActivityInstrumentationTestCase2
public void run() {
SpannableStringBuilder ssb = new SpannableStringBuilder();
ssb.append(sampleText);
- ssb.setSpan(suggestionSpan, spanStart, spanEnd, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ ssb.setSpan(singleWordSuggestionSpan, singleWordSpanStart, singleWordSpanEnd,
+ Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ ssb.setSpan(multiWordSuggestionSpan, multiWordSpanStart, multiWordSpanEnd,
+ Spanned.SPAN_INCLUSIVE_INCLUSIVE);
editText.setText(ssb);
- Selection.setSelection(editText.getText(), spanStart, spanEnd);
+ Selection.setSelection(editText.getText(), singleWordSpanStart, singleWordSpanEnd);
editText.onTextContextMenuItem(TextView.ID_REPLACE);
}
});
getInstrumentation().waitForIdleSync();
// In this test, the SuggestionsPopupWindow looks like
- // abc def ghi
- // ----------
- // | *DEF* |
- // | *Def* |
- // | DELETE |
- // ----------
+ // abc def ghi
+ // -----------------
+ // | abc *DEF* ghi |
+ // | abc *Def* ghi |
+ // | *ABC DEF GHI* |
+ // | *Abc Def Ghi* |
+ // | DELETE |
+ // -----------------
// *XX* means that XX is highlighted.
activity.runOnUiThread(new Runnable() {
public void run() {
@@ -90,9 +102,10 @@ public class SuggestionsPopupWindowTest extends ActivityInstrumentationTestCase2
int childNum = listView.getChildCount();
// +1 for "DELETE" command.
- assertEquals(candidate.length + 1, childNum);
+ assertEquals(singleWordCandidates.length + multiWordCandidates.length + 1,
+ childNum);
- for (int i = 0; i < candidate.length; ++i) {
+ for (int i = 0; i < singleWordCandidates.length; ++i) {
TextView textView = (TextView) listView.getChildAt(i);
assertNotNull(textView);
@@ -100,16 +113,46 @@ public class SuggestionsPopupWindowTest extends ActivityInstrumentationTestCase2
assertNotNull(spanned);
// Check that the suggestion item order is kept.
- assertEquals(candidate[i], spanned.toString());
+ String expectedText = "abc " + singleWordCandidates[i] + " ghi";
+ assertEquals(expectedText, spanned.toString());
+
+ // Check that the text is highlighted with correct color and text size.
+ TextAppearanceSpan[] taSpan = spanned.getSpans(singleWordSpanStart,
+ singleWordSpanEnd, TextAppearanceSpan.class);
+ assertEquals(1, taSpan.length);
+ TextPaint tp = new TextPaint();
+ taSpan[0].updateDrawState(tp);
+ assertEquals(expectedHighlightTextColor, tp.getColor());
+ assertEquals(expectedHighlightTextSize, tp.getTextSize());
+
+ // Check only center word is highlighted.
+ assertEquals(singleWordSpanStart, spanned.getSpanStart(taSpan[0]));
+ assertEquals(singleWordSpanEnd, spanned.getSpanEnd(taSpan[0]));
+ }
+
+ for (int i = 0; i < multiWordCandidates.length; ++i) {
+ int indexInListView = singleWordCandidates.length + i;
+ TextView textView = (TextView) listView.getChildAt(indexInListView);
+ assertNotNull(textView);
+
+ Spanned spanned = (Spanned) textView.getText();
+ assertNotNull(spanned);
+
+ // Check that the suggestion item order is kept.
+ assertEquals(multiWordCandidates[i], spanned.toString());
// Check that the text is highlighted with correct color and text size.
- TextAppearanceSpan[] taSpan = spanned.getSpans(0, candidate[i].length(),
- TextAppearanceSpan.class);
+ TextAppearanceSpan[] taSpan = spanned.getSpans(
+ 0, multiWordCandidates[i].length(), TextAppearanceSpan.class);
assertEquals(1, taSpan.length);
TextPaint tp = new TextPaint();
taSpan[0].updateDrawState(tp);
assertEquals(expectedHighlightTextColor, tp.getColor());
assertEquals(expectedHighlightTextSize, tp.getTextSize());
+
+ // Check the whole text is highlighted.
+ assertEquals(multiWordSpanStart, spanned.getSpanStart(taSpan[0]));
+ assertEquals(multiWordSpanEnd, spanned.getSpanEnd(taSpan[0]));
}
}
});
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
index 54117df35a01..ce9ae02c9cec 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
@@ -16,8 +16,13 @@
package android.widget;
+import static android.widget.espresso.TextViewActions.clickOnTextAtIndex;
+import static android.widget.espresso.TextViewActions.doubleTapAndDragOnText;
+import static android.widget.espresso.TextViewActions.longPressAndDragOnText;
+import static android.widget.espresso.TextViewAssertions.hasSelection;
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;
import static android.support.test.espresso.action.ViewActions.typeTextIntoFocusedView;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
@@ -27,6 +32,7 @@ import com.android.frameworks.coretests.R;
import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.SmallTest;
+import android.view.KeyEvent;
/**
* Tests the TextView widget from an Activity
@@ -47,4 +53,41 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV
onView(withId(R.id.textview)).check(matches(withText(helloWorld)));
}
+
+ @SmallTest
+ public void testPositionCursorAtTextAtIndex() throws Exception {
+ getActivity();
+
+ final String helloWorld = "Hello world!";
+ onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
+ onView(withId(R.id.textview)).perform(clickOnTextAtIndex(helloWorld.indexOf("world")));
+
+ // Delete text at specified index and see if we got the right one.
+ onView(withId(R.id.textview)).perform(pressKey(KeyEvent.KEYCODE_FORWARD_DEL));
+ onView(withId(R.id.textview)).check(matches(withText("Hello orld!")));
+ }
+
+ @SmallTest
+ public void testLongPressAndDragToSelect() throws Exception {
+ getActivity();
+
+ final String helloWorld = "Hello little handsome boy!";
+ onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
+ onView(withId(R.id.textview)).perform(
+ longPressAndDragOnText(helloWorld.indexOf("little"), helloWorld.indexOf(" boy!")));
+
+ onView(withId(R.id.textview)).check(hasSelection("little handsome"));
+ }
+
+ @SmallTest
+ public void testDoubleTapAndDragToSelect() throws Exception {
+ getActivity();
+
+ final String helloWorld = "Hello young beautiful girl!";
+ 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"));
+ }
}
diff --git a/core/tests/coretests/src/android/widget/TextViewWordLimitsTest.java b/core/tests/coretests/src/android/widget/TextViewWordLimitsTest.java
deleted file mode 100644
index 4b6616430e43..000000000000
--- a/core/tests/coretests/src/android/widget/TextViewWordLimitsTest.java
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
-*/
-
-package android.widget;
-
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.Suppress;
-import android.text.InputType;
-import android.text.Selection;
-import android.text.Spannable;
-import android.text.SpannableString;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-
-/**
- * TextViewPatchTest tests {@link TextView}'s definition of word. Finds and
- * verifies word limits to be in strings containing different kinds of
- * characters.
- */
-@Suppress // Failing.
-public class TextViewWordLimitsTest extends AndroidTestCase {
-
- TextView mTv = null;
- Method mGetWordLimits, mSelectCurrentWord;
- Field mContextMenuTriggeredByKey, mSelectionControllerEnabled;
-
-
- /**
- * Sets up common fields used in all test cases.
- * @throws NoSuchFieldException
- * @throws SecurityException
- */
- @Override
- protected void setUp() throws NoSuchMethodException, SecurityException, NoSuchFieldException {
- mTv = new TextView(getContext());
- mTv.setInputType(InputType.TYPE_CLASS_TEXT);
-
- mGetWordLimits = mTv.getClass().getDeclaredMethod("getWordLimitsAt",
- new Class[] {int.class});
- mGetWordLimits.setAccessible(true);
-
- mSelectCurrentWord = mTv.getClass().getDeclaredMethod("selectCurrentWord", new Class[] {});
- mSelectCurrentWord.setAccessible(true);
-
- mContextMenuTriggeredByKey = mTv.getClass().getDeclaredField("mContextMenuTriggeredByKey");
- mContextMenuTriggeredByKey.setAccessible(true);
- mSelectionControllerEnabled = mTv.getClass().getDeclaredField("mSelectionControllerEnabled");
- mSelectionControllerEnabled.setAccessible(true);
- }
-
- /**
- * Calculate and verify word limits. Depends on the TextView implementation.
- * Uses a private method and internal data representation.
- *
- * @param text Text to select a word from
- * @param pos Position to expand word around
- * @param correctStart Correct start position for the word
- * @param correctEnd Correct end position for the word
- * @throws InvocationTargetException
- * @throws IllegalAccessException
- * @throws IllegalArgumentException
- * @throws InvocationTargetException
- * @throws IllegalAccessException
- */
- private void verifyWordLimits(String text, int pos, int correctStart, int correctEnd)
- throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
- mTv.setText(text, TextView.BufferType.SPANNABLE);
-
- long limits = (Long)mGetWordLimits.invoke(mTv, new Object[] {new Integer(pos)});
- int actualStart = (int)(limits >>> 32);
- int actualEnd = (int)(limits & 0x00000000FFFFFFFFL);
- assertEquals(correctStart, actualStart);
- assertEquals(correctEnd, actualEnd);
- }
-
-
- private void verifySelectCurrentWord(Spannable text, int selectionStart, int selectionEnd, int correctStart,
- int correctEnd) throws InvocationTargetException, IllegalAccessException {
- mTv.setText(text, TextView.BufferType.SPANNABLE);
-
- Selection.setSelection((Spannable)mTv.getText(), selectionStart, selectionEnd);
- mContextMenuTriggeredByKey.setBoolean(mTv, true);
- mSelectionControllerEnabled.setBoolean(mTv, true);
- mSelectCurrentWord.invoke(mTv);
-
- assertEquals(correctStart, mTv.getSelectionStart());
- assertEquals(correctEnd, mTv.getSelectionEnd());
- }
-
-
- /**
- * Corner cases for string length.
- */
- @LargeTest
- public void testLengths() throws Exception {
- final String ONE_TWO = "one two";
- final String EMPTY = "";
- final String TOOLONG = "ThisWordIsTooLongToBeDefinedAsAWordInTheSenseUsedInTextView";
-
- // Select first word
- verifyWordLimits(ONE_TWO, 0, 0, 3);
- verifyWordLimits(ONE_TWO, 3, 0, 3);
-
- // Select last word
- verifyWordLimits(ONE_TWO, 4, 4, 7);
- verifyWordLimits(ONE_TWO, 7, 4, 7);
-
- // Empty string
- verifyWordLimits(EMPTY, 0, -1, -1);
-
- // Too long word
- verifyWordLimits(TOOLONG, 0, -1, -1);
- }
-
- /**
- * Unicode classes included.
- */
- @LargeTest
- public void testIncludedClasses() throws Exception {
- final String LOWER = "njlj";
- final String UPPER = "NJLJ";
- final String TITLECASE = "\u01C8\u01CB\u01F2"; // Lj Nj Dz
- final String OTHER = "\u3042\u3044\u3046"; // Hiragana AIU
- final String MODIFIER = "\u02C6\u02CA\u02CB"; // Circumflex Acute Grave
-
- // Each string contains a single valid word
- verifyWordLimits(LOWER, 1, 0, 4);
- verifyWordLimits(UPPER, 1, 0, 4);
- verifyWordLimits(TITLECASE, 1, 0, 3);
- verifyWordLimits(OTHER, 1, 0, 3);
- verifyWordLimits(MODIFIER, 1, 0, 3);
- }
-
- /**
- * Unicode classes included if combined with a letter.
- */
- @LargeTest
- public void testPartlyIncluded() throws Exception {
- final String NUMBER = "123";
- final String NUMBER_LOWER = "1st";
- final String APOSTROPHE = "''";
- final String APOSTROPHE_LOWER = "'Android's'";
-
- // Pure decimal number is ignored
- verifyWordLimits(NUMBER, 1, -1, -1);
-
- // Number with letter is valid
- verifyWordLimits(NUMBER_LOWER, 1, 0, 3);
-
- // Stand apostrophes are ignore
- verifyWordLimits(APOSTROPHE, 1, -1, -1);
-
- // Apostrophes are accepted if they are a part of a word
- verifyWordLimits(APOSTROPHE_LOWER, 1, 0, 11);
- }
-
- /**
- * Unicode classes included if combined with a letter.
- */
- @LargeTest
- public void testFinalSeparator() throws Exception {
- final String PUNCTUATION = "abc, def.";
-
- // Starting from the comma
- verifyWordLimits(PUNCTUATION, 3, 0, 3);
- verifyWordLimits(PUNCTUATION, 4, 0, 4);
-
- // Starting from the final period
- verifyWordLimits(PUNCTUATION, 8, 5, 8);
- verifyWordLimits(PUNCTUATION, 9, 5, 9);
- }
-
- /**
- * Unicode classes other than listed in testIncludedClasses and
- * testPartlyIncluded act as word separators.
- */
- @LargeTest
- public void testNotIncluded() throws Exception {
- // Selection of character classes excluded
- final String MARK_NONSPACING = "a\u030A"; // a Combining ring above
- final String PUNCTUATION_OPEN_CLOSE = "(c)"; // Parenthesis
- final String PUNCTUATION_DASH = "non-fiction"; // Hyphen
- final String PUNCTUATION_OTHER = "b&b"; // Ampersand
- final String SYMBOL_OTHER = "Android\u00AE"; // Registered
- final String SEPARATOR_SPACE = "one two"; // Space
-
- // "a"
- verifyWordLimits(MARK_NONSPACING, 1, 0, 1);
-
- // "c"
- verifyWordLimits(PUNCTUATION_OPEN_CLOSE, 1, 1, 2);
-
- // "non-"
- verifyWordLimits(PUNCTUATION_DASH, 3, 0, 3);
- verifyWordLimits(PUNCTUATION_DASH, 4, 4, 11);
-
- // "b"
- verifyWordLimits(PUNCTUATION_OTHER, 0, 0, 1);
- verifyWordLimits(PUNCTUATION_OTHER, 1, 0, 1);
- verifyWordLimits(PUNCTUATION_OTHER, 2, 0, 3); // & is considered a punctuation sign.
- verifyWordLimits(PUNCTUATION_OTHER, 3, 2, 3);
-
- // "Android"
- verifyWordLimits(SYMBOL_OTHER, 7, 0, 7);
- verifyWordLimits(SYMBOL_OTHER, 8, -1, -1);
-
- // "one"
- verifyWordLimits(SEPARATOR_SPACE, 1, 0, 3);
- }
-
- /**
- * Surrogate characters are treated as their code points.
- */
- @LargeTest
- public void testSurrogate() throws Exception {
- final String SURROGATE_LETTER = "\uD800\uDC00\uD800\uDC01\uD800\uDC02"; // Linear B AEI
- final String SURROGATE_SYMBOL = "\uD83D\uDE01\uD83D\uDE02\uD83D\uDE03"; // Three smileys
-
- // Letter Other is included even when coded as surrogate pairs
- verifyWordLimits(SURROGATE_LETTER, 0, 0, 6);
- verifyWordLimits(SURROGATE_LETTER, 1, 0, 6);
- verifyWordLimits(SURROGATE_LETTER, 2, 0, 6);
- verifyWordLimits(SURROGATE_LETTER, 3, 0, 6);
- verifyWordLimits(SURROGATE_LETTER, 4, 0, 6);
- verifyWordLimits(SURROGATE_LETTER, 5, 0, 6);
- verifyWordLimits(SURROGATE_LETTER, 6, 0, 6);
-
- // Not included classes are ignored even when coded as surrogate pairs
- verifyWordLimits(SURROGATE_SYMBOL, 0, -1, -1);
- verifyWordLimits(SURROGATE_SYMBOL, 1, -1, -1);
- verifyWordLimits(SURROGATE_SYMBOL, 2, -1, -1);
- verifyWordLimits(SURROGATE_SYMBOL, 3, -1, -1);
- verifyWordLimits(SURROGATE_SYMBOL, 4, -1, -1);
- verifyWordLimits(SURROGATE_SYMBOL, 5, -1, -1);
- verifyWordLimits(SURROGATE_SYMBOL, 6, -1, -1);
- }
-
- /**
- * Selection is used if present and valid word.
- */
- @LargeTest
- public void testSelectCurrentWord() throws Exception {
- SpannableString textLower = new SpannableString("first second");
- SpannableString textOther = new SpannableString("\u3042\3044\3046"); // Hiragana AIU
- SpannableString textDash = new SpannableString("non-fiction"); // Hyphen
- SpannableString textPunctOther = new SpannableString("b&b"); // Ampersand
- SpannableString textSymbolOther = new SpannableString("Android\u00AE"); // Registered
-
- // Valid selection - Letter, Lower
- verifySelectCurrentWord(textLower, 2, 5, 0, 5);
-
- // Adding the space spreads to the second word
- verifySelectCurrentWord(textLower, 2, 6, 0, 12);
-
- // Valid selection -- Letter, Other
- verifySelectCurrentWord(textOther, 1, 2, 0, 5);
-
- // Zero-width selection is interpreted as a cursor and the selection is ignored
- verifySelectCurrentWord(textLower, 2, 2, 0, 5);
-
- // Hyphen is part of selection
- verifySelectCurrentWord(textDash, 2, 5, 0, 11);
-
- // Ampersand part of selection or not
- verifySelectCurrentWord(textPunctOther, 1, 2, 0, 3);
- verifySelectCurrentWord(textPunctOther, 1, 3, 0, 3);
-
- // (R) part of the selection
- verifySelectCurrentWord(textSymbolOther, 2, 7, 0, 7);
- verifySelectCurrentWord(textSymbolOther, 2, 8, 0, 8);
- }
-}
diff --git a/core/tests/coretests/src/android/widget/espresso/DragOnTextViewActions.java b/core/tests/coretests/src/android/widget/espresso/DragOnTextViewActions.java
new file mode 100644
index 000000000000..a0cd848a53f5
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/espresso/DragOnTextViewActions.java
@@ -0,0 +1,281 @@
+/*
+ * 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.matcher.ViewMatchers.isAssignableFrom;
+import static android.support.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed;
+import static com.android.internal.util.Preconditions.checkNotNull;
+import static org.hamcrest.Matchers.allOf;
+
+import android.annotation.Nullable;
+import android.os.SystemClock;
+import android.support.test.espresso.UiController;
+import android.support.test.espresso.PerformException;
+import android.support.test.espresso.ViewAction;
+import android.support.test.espresso.action.CoordinatesProvider;
+import android.support.test.espresso.action.GeneralClickAction;
+import android.support.test.espresso.action.MotionEvents;
+import android.support.test.espresso.action.PrecisionDescriber;
+import android.support.test.espresso.action.Press;
+import android.support.test.espresso.action.Swiper;
+import android.support.test.espresso.action.Tap;
+import android.support.test.espresso.util.HumanReadables;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.widget.TextView;
+import org.hamcrest.Matcher;
+
+
+/**
+ * Drags on text in a TextView using touch events.<br>
+ * <br>
+ * View constraints:
+ * <ul>
+ * <li>must be a TextView displayed on screen
+ * <ul>
+ */
+public final class DragOnTextViewActions implements ViewAction {
+
+ /**
+ * Executes different "drag on text" types to given positions.
+ */
+ public enum Drag implements Swiper {
+
+ /**
+ * Starts a drag with a long-press.
+ */
+ LONG_PRESS {
+ private DownMotionPerformer downMotion = new DownMotionPerformer() {
+ @Override
+ public MotionEvent perform(
+ UiController uiController, float[] coordinates, float[] precision) {
+ MotionEvent downEvent = MotionEvents.sendDown(
+ uiController, coordinates, precision)
+ .down;
+ // Duration before a press turns into a long press.
+ // Factor 1.5 is needed, otherwise a long press is not safely detected.
+ // See android.test.TouchUtils longClickView
+ long longPressTimeout = (long) (ViewConfiguration.getLongPressTimeout() * 1.5f);
+ uiController.loopMainThreadForAtLeast(longPressTimeout);
+ return downEvent;
+ }
+ };
+
+ @Override
+ public Status sendSwipe(
+ UiController uiController,
+ float[] startCoordinates, float[] endCoordinates, float[] precision) {
+ return sendLinearDrag(
+ uiController, downMotion, startCoordinates, endCoordinates, precision);
+ }
+
+ @Override
+ public String toString() {
+ return "long press and drag to select";
+ }
+ },
+
+ /**
+ * Starts a drag with a double-tap.
+ */
+ DOUBLE_TAP {
+ private DownMotionPerformer downMotion = new DownMotionPerformer() {
+ @Override
+ @Nullable
+ public MotionEvent perform(
+ UiController uiController, float[] coordinates, float[] precision) {
+ MotionEvent downEvent = MotionEvents.sendDown(
+ uiController, coordinates, precision)
+ .down;
+ try {
+ if (!MotionEvents.sendUp(uiController, downEvent)) {
+ String logMessage = "Injection of up event as part of the double tap " +
+ "failed. Sending cancel event.";
+ Log.d(TAG, logMessage);
+ MotionEvents.sendCancel(uiController, downEvent);
+ return null;
+ }
+
+ long doubleTapMinimumTimeout = ViewConfiguration.getDoubleTapMinTime();
+ uiController.loopMainThreadForAtLeast(doubleTapMinimumTimeout);
+
+ return MotionEvents.sendDown(uiController, coordinates, precision).down;
+ } finally {
+ downEvent.recycle();
+ }
+ }
+ };
+
+ @Override
+ public Status sendSwipe(
+ UiController uiController,
+ float[] startCoordinates, float[] endCoordinates, float[] precision) {
+ return sendLinearDrag(
+ uiController, downMotion, startCoordinates, endCoordinates, precision);
+ }
+
+ @Override
+ public String toString() {
+ return "double-tap and drag to select";
+ }
+ };
+
+ private static final String TAG = Drag.class.getSimpleName();
+
+ /** The number of move events to send for each drag. */
+ private static final int DRAG_STEP_COUNT = 10;
+
+ /** Length of time a drag should last for, in milliseconds. */
+ private static final int DRAG_DURATION = 1500;
+
+ private static Status sendLinearDrag(
+ UiController uiController, DownMotionPerformer downMotion,
+ float[] startCoordinates, float[] endCoordinates, float[] precision) {
+ float[][] steps = interpolate(startCoordinates, endCoordinates);
+ final int delayBetweenMovements = DRAG_DURATION / steps.length;
+
+ MotionEvent downEvent = downMotion.perform(uiController, startCoordinates, precision);
+ if (downEvent == null) {
+ return Status.FAILURE;
+ }
+
+ try {
+ for (int i = 0; i < steps.length; i++) {
+ if (!MotionEvents.sendMovement(uiController, downEvent, steps[i])) {
+ String logMessage = "Injection of move event as part of the drag failed. " +
+ "Sending cancel event.";
+ Log.e(TAG, logMessage);
+ MotionEvents.sendCancel(uiController, downEvent);
+ return Status.FAILURE;
+ }
+
+ long desiredTime = downEvent.getDownTime() + delayBetweenMovements * i;
+ long timeUntilDesired = desiredTime - SystemClock.uptimeMillis();
+ if (timeUntilDesired > 10) {
+ // If the wait time until the next event isn't long enough, skip the wait
+ // and execute the next event.
+ uiController.loopMainThreadForAtLeast(timeUntilDesired);
+ }
+ }
+
+ if (!MotionEvents.sendUp(uiController, downEvent, endCoordinates)) {
+ String logMessage = "Injection of up event as part of the drag failed. " +
+ "Sending cancel event.";
+ Log.e(TAG, logMessage);
+ MotionEvents.sendCancel(uiController, downEvent);
+ return Status.FAILURE;
+ }
+ } finally {
+ downEvent.recycle();
+ }
+ return Status.SUCCESS;
+ }
+
+ private static float[][] interpolate(float[] start, float[] end) {
+ float[][] res = new float[DRAG_STEP_COUNT][2];
+
+ for (int i = 1; i < DRAG_STEP_COUNT + 1; i++) {
+ res[i - 1][0] = start[0] + (end[0] - start[0]) * i / (DRAG_STEP_COUNT + 2f);
+ res[i - 1][1] = start[1] + (end[1] - start[1]) * i / (DRAG_STEP_COUNT + 2f);
+ }
+
+ return res;
+ }
+ }
+
+ /**
+ * Interface to implement different "down motion" types.
+ */
+ private interface DownMotionPerformer {
+ /**
+ * Performs and returns a down motion.
+ *
+ * @param uiController a UiController to use to send MotionEvents to the screen.
+ * @param coordinates a float[] with x and y values of center of the tap.
+ * @param precision a float[] with x and y values of precision of the tap.
+ * @return the down motion event or null if the down motion event failed.
+ */
+ @Nullable
+ MotionEvent perform(UiController uiController, float[] coordinates, float[] precision);
+ }
+
+ private final Swiper mDragger;
+ private final CoordinatesProvider mStartCoordinatesProvider;
+ private final CoordinatesProvider mEndCoordinatesProvider;
+ private final PrecisionDescriber mPrecisionDescriber;
+
+ public DragOnTextViewActions(
+ Swiper dragger,
+ CoordinatesProvider startCoordinatesProvider,
+ CoordinatesProvider endCoordinatesProvider,
+ PrecisionDescriber precisionDescriber) {
+ mDragger = checkNotNull(dragger);
+ mStartCoordinatesProvider = checkNotNull(startCoordinatesProvider);
+ mEndCoordinatesProvider = checkNotNull(endCoordinatesProvider);
+ mPrecisionDescriber = checkNotNull(precisionDescriber);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public Matcher<View> getConstraints() {
+ return allOf(isCompletelyDisplayed(), isAssignableFrom(TextView.class));
+ }
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ checkNotNull(uiController);
+ checkNotNull(view);
+
+ float[] startCoordinates = mStartCoordinatesProvider.calculateCoordinates(view);
+ float[] endCoordinates = mEndCoordinatesProvider.calculateCoordinates(view);
+ float[] precision = mPrecisionDescriber.describePrecision();
+
+ Swiper.Status status;
+
+ try {
+ status = mDragger.sendSwipe(
+ uiController, startCoordinates, endCoordinates, precision);
+ } catch (RuntimeException re) {
+ throw new PerformException.Builder()
+ .withActionDescription(this.getDescription())
+ .withViewDescription(HumanReadables.describe(view))
+ .withCause(re)
+ .build();
+ }
+
+ int duration = ViewConfiguration.getPressedStateDuration();
+ // ensures that all work enqueued to process the swipe has been run.
+ if (duration > 0) {
+ uiController.loopMainThreadForAtLeast(duration);
+ }
+
+ if (status == Swiper.Status.FAILURE) {
+ throw new PerformException.Builder()
+ .withActionDescription(getDescription())
+ .withViewDescription(HumanReadables.describe(view))
+ .withCause(new RuntimeException(getDescription() + " failed"))
+ .build();
+ }
+ }
+
+ @Override
+ public String getDescription() {
+ return mDragger.toString();
+ }
+}
diff --git a/core/tests/coretests/src/android/widget/espresso/TextViewActions.java b/core/tests/coretests/src/android/widget/espresso/TextViewActions.java
new file mode 100644
index 000000000000..7e4735b298fe
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/espresso/TextViewActions.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 android.widget.espresso;
+
+import static android.support.test.espresso.action.ViewActions.actionWithAssertions;
+
+import android.support.test.espresso.PerformException;
+import android.support.test.espresso.ViewAction;
+import android.support.test.espresso.action.CoordinatesProvider;
+import android.support.test.espresso.action.GeneralClickAction;
+import android.support.test.espresso.action.Press;
+import android.support.test.espresso.action.Tap;
+import android.support.test.espresso.util.HumanReadables;
+import android.text.Layout;
+import android.view.View;
+import android.widget.TextView;
+
+/**
+ * A collection of actions on a {@link android.widget.TextView}.
+ */
+public final class TextViewActions {
+
+ private TextViewActions() {}
+
+ /**
+ * Returns an action that 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 click on.
+ */
+ public static ViewAction clickOnTextAtIndex(int index) {
+ return actionWithAssertions(
+ new GeneralClickAction(Tap.SINGLE, new TextCoordinates(index), Press.FINGER));
+ }
+
+ /**
+ * Returns an action that long presses then drags on text from startIndex to endIndex on the
+ * TextView.<br>
+ * <br>
+ * View constraints:
+ * <ul>
+ * <li>must be a TextView displayed on screen
+ * <ul>
+ *
+ * @param startIndex The index of the TextView's text to start a drag from
+ * @param endIndex The index of the TextView's text to end the drag at
+ */
+ public static ViewAction longPressAndDragOnText(int startIndex, int endIndex) {
+ return actionWithAssertions(
+ new DragOnTextViewActions(
+ DragOnTextViewActions.Drag.LONG_PRESS,
+ new TextCoordinates(startIndex),
+ new TextCoordinates(endIndex),
+ Press.FINGER));
+ }
+
+ /**
+ * Returns an action that double taps then drags on text from startIndex to endIndex on the
+ * TextView.<br>
+ * <br>
+ * View constraints:
+ * <ul>
+ * <li>must be a TextView displayed on screen
+ * <ul>
+ *
+ * @param startIndex The index of the TextView's text to start a drag from
+ * @param endIndex The index of the TextView's text to end the drag at
+ */
+ public static ViewAction doubleTapAndDragOnText(int startIndex, int endIndex) {
+ return actionWithAssertions(
+ new DragOnTextViewActions(
+ DragOnTextViewActions.Drag.DOUBLE_TAP,
+ new TextCoordinates(startIndex),
+ new TextCoordinates(endIndex),
+ Press.FINGER));
+ }
+
+ /**
+ * A provider of the x, y coordinates of the text at the specified index in a text view.
+ */
+ private static final class TextCoordinates implements CoordinatesProvider {
+
+ private final int mIndex;
+ private final String mActionDescription;
+
+ public TextCoordinates(int index) {
+ mIndex = index;
+ mActionDescription = "Could not locate text at index: " + mIndex;
+ }
+
+ @Override
+ public float[] calculateCoordinates(View view) {
+ try {
+ return locateTextAtIndex((TextView) view, mIndex);
+ } catch (ClassCastException e) {
+ throw new PerformException.Builder()
+ .withActionDescription(mActionDescription)
+ .withViewDescription(HumanReadables.describe(view))
+ .withCause(e)
+ .build();
+ } catch (StringIndexOutOfBoundsException e) {
+ throw new PerformException.Builder()
+ .withActionDescription(mActionDescription)
+ .withViewDescription(HumanReadables.describe(view))
+ .withCause(e)
+ .build();
+ }
+ }
+
+ /**
+ * @throws StringIndexOutOfBoundsException
+ */
+ private float[] locateTextAtIndex(TextView textView, int index) {
+ if (index < 0 || index > textView.getText().length()) {
+ throw new StringIndexOutOfBoundsException(index);
+ }
+ final int[] xy = new int[2];
+ textView.getLocationOnScreen(xy);
+ final Layout layout = textView.getLayout();
+ final int line = layout.getLineForOffset(index);
+ final float x = textView.getTotalPaddingLeft() - textView.getScrollX()
+ + layout.getPrimaryHorizontal(index);
+ final float y = textView.getTotalPaddingTop() - textView.getScrollY()
+ + layout.getLineTop(line);
+ return new float[]{x + xy[0], y + xy[1]};
+ }
+ }
+}
diff --git a/core/tests/coretests/src/android/widget/espresso/TextViewAssertions.java b/core/tests/coretests/src/android/widget/espresso/TextViewAssertions.java
new file mode 100644
index 000000000000..dce3182693a6
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/espresso/TextViewAssertions.java
@@ -0,0 +1,98 @@
+/*
+ * 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.matcher.ViewMatchers.assertThat;
+import static com.android.internal.util.Preconditions.checkNotNull;
+import static org.hamcrest.Matchers.is;
+
+import android.support.test.espresso.NoMatchingViewException;
+import android.support.test.espresso.ViewAssertion;
+import android.view.View;
+import android.widget.TextView;
+
+import junit.framework.AssertionFailedError;
+import org.hamcrest.Matcher;
+
+/**
+ * A collection of assertions on a {@link android.widget.TextView}.
+ */
+public final class TextViewAssertions {
+
+ private TextViewAssertions() {}
+
+ /**
+ * Returns a {@link ViewAssertion} that asserts that the text view has a specified
+ * selection.<br>
+ * <br>
+ * View constraints:
+ * <ul>
+ * <li>must be a text view displayed on screen
+ * <ul>
+ *
+ * @param selection The expected selection.
+ */
+ public static ViewAssertion hasSelection(String selection) {
+ return new TextSelectionAssertion(is(selection));
+ }
+
+ /**
+ * Returns a {@link ViewAssertion} that asserts that the text view has a specified
+ * selection.<br>
+ * <br>
+ * View constraints:
+ * <ul>
+ * <li>must be a text view displayed on screen
+ * <ul>
+ *
+ * @param selection A matcher representing the expected selection.
+ */
+ public static ViewAssertion hasSelection(Matcher<String> selection) {
+ return new TextSelectionAssertion(selection);
+ }
+
+ /**
+ * A {@link ViewAssertion} to check the selected text in a {@link TextView}.
+ */
+ private static final class TextSelectionAssertion implements ViewAssertion {
+
+ private final Matcher<String> mSelection;
+
+ public TextSelectionAssertion(Matcher<String> selection) {
+ mSelection = checkNotNull(selection);
+ }
+
+ @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 {
+ String selectedText = textView.getText()
+ .subSequence(selectionStart, selectionEnd)
+ .toString();
+ assertThat(selectedText, mSelection);
+ } catch (IndexOutOfBoundsException e) {
+ throw new AssertionFailedError(e.getMessage());
+ }
+ } else {
+ throw new AssertionFailedError("TextView not found");
+ }
+ }
+ }
+}
diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java
index 5e7f127fd4a6..c279c8f24362 100644
--- a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java
+++ b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java
@@ -1075,4 +1075,120 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
assertTrue(subtypes2.isEmpty());
}
}
+
+ @SmallTest
+ public void testbuildInputMethodsAndSubtypesString() {
+ {
+ ArrayMap<String, ArraySet<String>> map = new ArrayMap<>();
+ assertEquals("", InputMethodUtils.buildInputMethodsAndSubtypesString(map));
+ }
+ {
+ ArrayMap<String, ArraySet<String>> map = new ArrayMap<>();
+ map.put("ime0", new ArraySet<String>());
+ assertEquals("ime0", InputMethodUtils.buildInputMethodsAndSubtypesString(map));
+ }
+ {
+ ArrayMap<String, ArraySet<String>> map = new ArrayMap<>();
+ ArraySet<String> subtypes1 = new ArraySet<>();
+ subtypes1.add("subtype0");
+ map.put("ime0", subtypes1);
+ assertEquals("ime0;subtype0", InputMethodUtils.buildInputMethodsAndSubtypesString(map));
+ }
+ {
+ ArrayMap<String, ArraySet<String>> map = new ArrayMap<>();
+ ArraySet<String> subtypes1 = new ArraySet<>();
+ subtypes1.add("subtype0");
+ subtypes1.add("subtype1");
+ map.put("ime0", subtypes1);
+
+ // We do not expect what order will be used to concatenate items in
+ // InputMethodUtils.buildInputMethodsAndSubtypesString() hence enumerate all possible
+ // permutations here.
+ ArraySet<String> validSequences = new ArraySet<>();
+ validSequences.add("ime0;subtype0;subtype1");
+ validSequences.add("ime0;subtype1;subtype0");
+ assertTrue(validSequences.contains(
+ InputMethodUtils.buildInputMethodsAndSubtypesString(map)));
+ }
+ {
+ ArrayMap<String, ArraySet<String>> map = new ArrayMap<>();
+ map.put("ime0", new ArraySet<String>());
+ map.put("ime1", new ArraySet<String>());
+
+ ArraySet<String> validSequences = new ArraySet<>();
+ validSequences.add("ime0:ime1");
+ validSequences.add("ime1:ime0");
+ assertTrue(validSequences.contains(
+ InputMethodUtils.buildInputMethodsAndSubtypesString(map)));
+ }
+ {
+ ArrayMap<String, ArraySet<String>> map = new ArrayMap<>();
+ ArraySet<String> subtypes1 = new ArraySet<>();
+ subtypes1.add("subtype0");
+ map.put("ime0", subtypes1);
+ map.put("ime1", new ArraySet<String>());
+
+ ArraySet<String> validSequences = new ArraySet<>();
+ validSequences.add("ime0;subtype0:ime1");
+ validSequences.add("ime1;ime0;subtype0");
+ assertTrue(validSequences.contains(
+ InputMethodUtils.buildInputMethodsAndSubtypesString(map)));
+ }
+ {
+ ArrayMap<String, ArraySet<String>> map = new ArrayMap<>();
+ ArraySet<String> subtypes1 = new ArraySet<>();
+ subtypes1.add("subtype0");
+ subtypes1.add("subtype1");
+ map.put("ime0", subtypes1);
+ map.put("ime1", new ArraySet<String>());
+
+ ArraySet<String> validSequences = new ArraySet<>();
+ validSequences.add("ime0;subtype0;subtype1:ime1");
+ validSequences.add("ime0;subtype1;subtype0:ime1");
+ validSequences.add("ime1:ime0;subtype0;subtype1");
+ validSequences.add("ime1:ime0;subtype1;subtype0");
+ assertTrue(validSequences.contains(
+ InputMethodUtils.buildInputMethodsAndSubtypesString(map)));
+ }
+ {
+ ArrayMap<String, ArraySet<String>> map = new ArrayMap<>();
+ ArraySet<String> subtypes1 = new ArraySet<>();
+ subtypes1.add("subtype0");
+ map.put("ime0", subtypes1);
+
+ ArraySet<String> subtypes2 = new ArraySet<>();
+ subtypes2.add("subtype1");
+ map.put("ime1", subtypes2);
+
+ ArraySet<String> validSequences = new ArraySet<>();
+ validSequences.add("ime0;subtype0:ime1;subtype1");
+ validSequences.add("ime1;subtype1:ime0;subtype0");
+ assertTrue(validSequences.contains(
+ InputMethodUtils.buildInputMethodsAndSubtypesString(map)));
+ }
+ {
+ ArrayMap<String, ArraySet<String>> map = new ArrayMap<>();
+ ArraySet<String> subtypes1 = new ArraySet<>();
+ subtypes1.add("subtype0");
+ subtypes1.add("subtype1");
+ map.put("ime0", subtypes1);
+
+ ArraySet<String> subtypes2 = new ArraySet<>();
+ subtypes2.add("subtype2");
+ subtypes2.add("subtype3");
+ map.put("ime1", subtypes2);
+
+ ArraySet<String> validSequences = new ArraySet<>();
+ validSequences.add("ime0;subtype0;subtype1:ime1;subtype2;subtype3");
+ validSequences.add("ime0;subtype1;subtype0:ime1;subtype2;subtype3");
+ validSequences.add("ime0;subtype0;subtype1:ime1;subtype3;subtype2");
+ validSequences.add("ime0;subtype1;subtype0:ime1;subtype3;subtype2");
+ validSequences.add("ime1;subtype2;subtype3:ime0;subtype0;subtype1");
+ validSequences.add("ime2;subtype3;subtype2:ime0;subtype0;subtype1");
+ validSequences.add("ime3;subtype2;subtype3:ime0;subtype1;subtype0");
+ validSequences.add("ime4;subtype3;subtype2:ime0;subtype1;subtype0");
+ assertTrue(validSequences.contains(
+ InputMethodUtils.buildInputMethodsAndSubtypesString(map)));
+ }
+ }
}
diff --git a/core/tests/hosttests/test-apps/SharedUid/32/jni/native.cpp b/core/tests/hosttests/test-apps/SharedUid/32/jni/native.cpp
index 4c1615453289..67b12d775828 100644
--- a/core/tests/hosttests/test-apps/SharedUid/32/jni/native.cpp
+++ b/core/tests/hosttests/test-apps/SharedUid/32/jni/native.cpp
@@ -30,7 +30,7 @@ int result = a + b;
static const char *classPathName = "com/framework/shareduid/bit32/Native";
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
{"add", "(II)I", (void*)add },
};
@@ -38,7 +38,7 @@ static JNINativeMethod methods[] = {
* Register several native methods for one class.
*/
static int registerNativeMethods(JNIEnv* env, const char* className,
- JNINativeMethod* gMethods, int numMethods)
+ const JNINativeMethod* gMethods, int numMethods)
{
jclass clazz;
diff --git a/core/tests/hosttests/test-apps/SharedUid/64/jni/native.cpp b/core/tests/hosttests/test-apps/SharedUid/64/jni/native.cpp
index c2f9f529ee63..342b3bc0ac9a 100644
--- a/core/tests/hosttests/test-apps/SharedUid/64/jni/native.cpp
+++ b/core/tests/hosttests/test-apps/SharedUid/64/jni/native.cpp
@@ -30,7 +30,7 @@ int result = a + b;
static const char *classPathName = "com/framework/shareduid/bit64/Native";
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
{"add", "(II)I", (void*)add },
};
@@ -38,7 +38,7 @@ static JNINativeMethod methods[] = {
* Register several native methods for one class.
*/
static int registerNativeMethods(JNIEnv* env, const char* className,
- JNINativeMethod* gMethods, int numMethods)
+ const JNINativeMethod* gMethods, int numMethods)
{
jclass clazz;
diff --git a/core/tests/hosttests/test-apps/SharedUid/dual/jni/native.cpp b/core/tests/hosttests/test-apps/SharedUid/dual/jni/native.cpp
index 5d3ca06968eb..9b38e3e4c437 100644
--- a/core/tests/hosttests/test-apps/SharedUid/dual/jni/native.cpp
+++ b/core/tests/hosttests/test-apps/SharedUid/dual/jni/native.cpp
@@ -30,7 +30,7 @@ int result = a + b;
static const char *classPathName = "com/framework/shareduid/dual/Native";
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
{"add", "(II)I", (void*)add },
};
@@ -38,7 +38,7 @@ static JNINativeMethod methods[] = {
* Register several native methods for one class.
*/
static int registerNativeMethods(JNIEnv* env, const char* className,
- JNINativeMethod* gMethods, int numMethods)
+ const JNINativeMethod* gMethods, int numMethods)
{
jclass clazz;
diff --git a/docs/html/guide/topics/renderscript/reference/rs_for_each.jd b/docs/html/guide/topics/renderscript/reference/rs_for_each.jd
index abbbda78ba3a..9ba56149f142 100644
--- a/docs/html/guide/topics/renderscript/reference/rs_for_each.jd
+++ b/docs/html/guide/topics/renderscript/reference/rs_for_each.jd
@@ -205,7 +205,7 @@ locality when the processing is distributed over multiple cores.
<span class='normal'>: Handle to a kernel invocation context</span>
</h4>
<div class='jd-details-descr'>
-<p>A typedef of: const struct rs_kernel_context_t *&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 23</a>
+<p>A typedef of: const struct rs_kernel_context_t *&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 23</a>
</p>
<p> The kernel context contains common characteristics of the allocations being iterated
over, like dimensions. It also contains rarely used indices of the currently processed
diff --git a/docs/html/guide/topics/renderscript/reference/rs_graphics.jd b/docs/html/guide/topics/renderscript/reference/rs_graphics.jd
index 1b115fe9a793..b04451c7a526 100644
--- a/docs/html/guide/topics/renderscript/reference/rs_graphics.jd
+++ b/docs/html/guide/topics/renderscript/reference/rs_graphics.jd
@@ -502,7 +502,7 @@ page.title=RenderScript Graphics Functions and Types
</h4>
<div class='jd-details-descr'>
<p>An enum with the following values:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- When compiling for 32 bits. <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 16 - 22</a>
+When compiling for 32 bits. <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 16 - 22</a>
</p>
<table class='jd-tagtable'><tbody>
<tr><th>RS_BLEND_DST_ZERO = 0</th><td></td></tr>
@@ -527,7 +527,7 @@ page.title=RenderScript Graphics Functions and Types
</h4>
<div class='jd-details-descr'>
<p>An enum with the following values:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- When compiling for 32 bits. <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 16 - 22</a>
+When compiling for 32 bits. <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 16 - 22</a>
</p>
<table class='jd-tagtable'><tbody>
<tr><th>RS_BLEND_SRC_ZERO = 0</th><td></td></tr>
@@ -553,7 +553,7 @@ page.title=RenderScript Graphics Functions and Types
</h4>
<div class='jd-details-descr'>
<p>An enum with the following values:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- When compiling for 32 bits. <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 16 - 22</a>
+When compiling for 32 bits. <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 16 - 22</a>
</p>
<table class='jd-tagtable'><tbody>
<tr><th>RS_CULL_BACK = 0</th><td></td></tr>
@@ -573,7 +573,7 @@ page.title=RenderScript Graphics Functions and Types
</h4>
<div class='jd-details-descr'>
<p>An enum with the following values:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- When compiling for 32 bits. <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 16 - 22</a>
+When compiling for 32 bits. <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 16 - 22</a>
</p>
<table class='jd-tagtable'><tbody>
<tr><th>RS_DEPTH_FUNC_ALWAYS = 0</th><td>Always drawn</td></tr>
@@ -599,11 +599,7 @@ depth to that found in the depth buffer.
<span class='normal'>: Handle to a Font</span>
</h4>
<div class='jd-details-descr'>
-<p>A typedef of: _RS_HANDLE __attribute__((
-#if (defined(RS_VERSION) && (RS_VERSION >= 1))
-deprecated
-#endif
-))&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; When compiling for 32 bits. Removed from <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 23 and higher</a>
+<p>When compiling for 32 bits. Removed from <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 23 and higher</a>
</p>
<p><b>Deprecated.</b> Do not use.</p>
<p> Opaque handle to a RenderScript font object.
@@ -619,11 +615,7 @@ See: android.renderscript.Font
<span class='normal'>: Handle to a Mesh</span>
</h4>
<div class='jd-details-descr'>
-<p>A typedef of: _RS_HANDLE __attribute__((
-#if (defined(RS_VERSION) && (RS_VERSION >= 1))
-deprecated
-#endif
-))&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; When compiling for 32 bits. Removed from <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 23 and higher</a>
+<p>When compiling for 32 bits. Removed from <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 23 and higher</a>
</p>
<p><b>Deprecated.</b> Do not use.</p>
<p> Opaque handle to a RenderScript mesh object.
@@ -640,7 +632,7 @@ See: android.renderscript.Mesh
</h4>
<div class='jd-details-descr'>
<p>An enum with the following values:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- When compiling for 32 bits. <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 16 - 22</a>
+When compiling for 32 bits. <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 16 - 22</a>
</p>
<table class='jd-tagtable'><tbody>
<tr><th>RS_PRIMITIVE_POINT = 0</th><td>Vertex data will be rendered as a series of points</td></tr>
@@ -664,11 +656,7 @@ See: android.renderscript.Mesh
<span class='normal'>: Handle to a ProgramFragment</span>
</h4>
<div class='jd-details-descr'>
-<p>A typedef of: _RS_HANDLE __attribute__((
-#if (defined(RS_VERSION) && (RS_VERSION >= 1))
-deprecated
-#endif
-))&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; When compiling for 32 bits. Removed from <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 23 and higher</a>
+<p>When compiling for 32 bits. Removed from <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 23 and higher</a>
</p>
<p><b>Deprecated.</b> Do not use.</p>
<p> Opaque handle to a RenderScript ProgramFragment object.
@@ -684,11 +672,7 @@ See: android.renderscript.ProgramFragment
<span class='normal'>: Handle to a ProgramRaster</span>
</h4>
<div class='jd-details-descr'>
-<p>A typedef of: _RS_HANDLE __attribute__((
-#if (defined(RS_VERSION) && (RS_VERSION >= 1))
-deprecated
-#endif
-))&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; When compiling for 32 bits. Removed from <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 23 and higher</a>
+<p>When compiling for 32 bits. Removed from <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 23 and higher</a>
</p>
<p><b>Deprecated.</b> Do not use.</p>
<p> Opaque handle to a RenderScript ProgramRaster object.
@@ -704,11 +688,7 @@ See: android.renderscript.ProgramRaster
<span class='normal'>: Handle to a ProgramStore</span>
</h4>
<div class='jd-details-descr'>
-<p>A typedef of: _RS_HANDLE __attribute__((
-#if (defined(RS_VERSION) && (RS_VERSION >= 1))
-deprecated
-#endif
-))&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; When compiling for 32 bits. Removed from <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 23 and higher</a>
+<p>When compiling for 32 bits. Removed from <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 23 and higher</a>
</p>
<p><b>Deprecated.</b> Do not use.</p>
<p> Opaque handle to a RenderScript ProgramStore object.
@@ -724,11 +704,7 @@ See: android.renderscript.ProgramStore
<span class='normal'>: Handle to a ProgramVertex</span>
</h4>
<div class='jd-details-descr'>
-<p>A typedef of: _RS_HANDLE __attribute__((
-#if (defined(RS_VERSION) && (RS_VERSION >= 1))
-deprecated
-#endif
-))&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; When compiling for 32 bits. Removed from <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 23 and higher</a>
+<p>When compiling for 32 bits. Removed from <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 23 and higher</a>
</p>
<p><b>Deprecated.</b> Do not use.</p>
<p> Opaque handle to a RenderScript ProgramVertex object.
diff --git a/docs/html/guide/topics/renderscript/reference/rs_object_types.jd b/docs/html/guide/topics/renderscript/reference/rs_object_types.jd
index f3428966c7de..ac4745482d1f 100644
--- a/docs/html/guide/topics/renderscript/reference/rs_object_types.jd
+++ b/docs/html/guide/topics/renderscript/reference/rs_object_types.jd
@@ -99,7 +99,7 @@ elements, and scripts. Most of these object are created using the Java RenderSc
<span class='normal'>: Handle to an allocation</span>
</h4>
<div class='jd-details-descr'>
-<p>A typedef of: _RS_HANDLE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p>
+<p></p>
<p> An opaque handle to a RenderScript allocation.
</p>
@@ -116,7 +116,7 @@ elements, and scripts. Most of these object are created using the Java RenderSc
</h4>
<div class='jd-details-descr'>
<p>An enum with the following values:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 14</a>
+Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 14</a>
</p>
<table class='jd-tagtable'><tbody>
<tr><th>RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X = 0</th><td></td></tr>
@@ -139,7 +139,7 @@ elements, and scripts. Most of these object are created using the Java RenderSc
</h4>
<div class='jd-details-descr'>
<p>An enum with the following values:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 14</a>
+Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 14</a>
</p>
<table class='jd-tagtable'><tbody>
<tr><th>RS_ALLOCATION_USAGE_SCRIPT = 0x0001</th><td>Allocation is bound to and accessed by scripts.</td></tr>
@@ -165,7 +165,7 @@ relevant to an allocation or an operation on an allocation.
</h4>
<div class='jd-details-descr'>
<p>An enum with the following values:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 16</a>
+Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 16</a>
</p>
<table class='jd-tagtable'><tbody>
<tr><th>RS_KIND_USER = 0</th><td>No special interpretation.</td></tr>
@@ -202,7 +202,7 @@ texture formats.
</h4>
<div class='jd-details-descr'>
<p>An enum with the following values:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 16</a>
+Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 16</a>
</p>
<table class='jd-tagtable'><tbody>
<tr><th>RS_TYPE_NONE = 0</th><td>Element is a complex type, i.e. a struct.</td></tr>
@@ -253,7 +253,7 @@ as a single unit for packing and alignment purposes.
<span class='normal'>: Handle to an element</span>
</h4>
<div class='jd-details-descr'>
-<p>A typedef of: _RS_HANDLE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p>
+<p></p>
<p> An opaque handle to a RenderScript element.
</p>
@@ -269,7 +269,7 @@ as a single unit for packing and alignment purposes.
<span class='normal'>: Handle to a Sampler</span>
</h4>
<div class='jd-details-descr'>
-<p>A typedef of: _RS_HANDLE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p>
+<p></p>
<p> An opaque handle to a RenderScript sampler object.
</p>
@@ -286,7 +286,7 @@ as a single unit for packing and alignment purposes.
</h4>
<div class='jd-details-descr'>
<p>An enum with the following values:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 16</a>
+Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 16</a>
</p>
<table class='jd-tagtable'><tbody>
<tr><th>RS_SAMPLER_NEAREST = 0</th><td></td></tr>
@@ -308,7 +308,7 @@ as a single unit for packing and alignment purposes.
<span class='normal'>: Handle to a Script</span>
</h4>
<div class='jd-details-descr'>
-<p>A typedef of: _RS_HANDLE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p>
+<p></p>
<p> An opaque handle to a RenderScript script object.
</p>
@@ -324,7 +324,7 @@ as a single unit for packing and alignment purposes.
<span class='normal'>: Handle to a Type</span>
</h4>
<div class='jd-details-descr'>
-<p>A typedef of: _RS_HANDLE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p>
+<p></p>
<p> An opaque handle to a RenderScript type.
</p>
diff --git a/docs/html/guide/topics/renderscript/reference/rs_time.jd b/docs/html/guide/topics/renderscript/reference/rs_time.jd
index 27044a3d3126..a1cedfb954db 100644
--- a/docs/html/guide/topics/renderscript/reference/rs_time.jd
+++ b/docs/html/guide/topics/renderscript/reference/rs_time.jd
@@ -78,9 +78,9 @@ system up time. It is not recommended to call these functions inside of a kerne
<span class='normal'>: Seconds since January 1, 1970</span>
</h4>
<div class='jd-details-descr'>
-<p>A typedef of: int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; When compiling for 32 bits.
+<p>A typedef of: int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;When compiling for 32 bits.
</p>
-<p>A typedef of: long&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; When compiling for 64 bits.
+<p>A typedef of: long&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;When compiling for 64 bits.
</p>
<p> Calendar time interpreted as seconds elapsed since the Epoch (00:00:00 on
January 1, 1970, Coordinated Universal Time (UTC)).
diff --git a/docs/html/guide/topics/renderscript/reference/rs_value_types.jd b/docs/html/guide/topics/renderscript/reference/rs_value_types.jd
index d53caf92d74a..2bd49dc5cf7c 100644
--- a/docs/html/guide/topics/renderscript/reference/rs_value_types.jd
+++ b/docs/html/guide/topics/renderscript/reference/rs_value_types.jd
@@ -644,7 +644,7 @@ with a 128 bit alignment.
<span class='normal'>: 16 bit floating point value</span>
</h4>
<div class='jd-details-descr'>
-<p>A typedef of: __fp16&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 23</a>
+<p>A typedef of: __fp16&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 23</a>
</p>
<p> A 16 bit floating point value.
</p>
@@ -658,7 +658,7 @@ with a 128 bit alignment.
<span class='normal'>: Two 16 bit floats</span>
</h4>
<div class='jd-details-descr'>
-<p>A typedef of: half __attribute__((ext_vector_type(2)))&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 23</a>
+<p>A typedef of: half __attribute__((ext_vector_type(2)))&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 23</a>
</p>
<p> Vector version of the half float type. Provides two half fields packed
into a single 32 bit field with 32 bit alignment.
@@ -673,7 +673,7 @@ into a single 32 bit field with 32 bit alignment.
<span class='normal'>: Three 16 bit floats</span>
</h4>
<div class='jd-details-descr'>
-<p>A typedef of: half __attribute__((ext_vector_type(3)))&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 23</a>
+<p>A typedef of: half __attribute__((ext_vector_type(3)))&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 23</a>
</p>
<p> Vector version of the half float type. Provides three half fields packed
into a single 64 bit field with 64 bit alignment.
@@ -688,7 +688,7 @@ into a single 64 bit field with 64 bit alignment.
<span class='normal'>: Four 16 bit floats</span>
</h4>
<div class='jd-details-descr'>
-<p>A typedef of: half __attribute__((ext_vector_type(4)))&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 23</a>
+<p>A typedef of: half __attribute__((ext_vector_type(4)))&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 23</a>
</p>
<p> Vector version of the half float type. Provides four half fields packed
into a single 64 bit field with 64 bit alignment.
@@ -771,9 +771,9 @@ with a 128 bit alignment.
<span class='normal'>: 64 bit signed integer</span>
</h4>
<div class='jd-details-descr'>
-<p>A typedef of: long long&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Removed from <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 21 and higher</a>
+<p>A typedef of: long long&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Removed from <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 21 and higher</a>
</p>
-<p>A typedef of: long&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 21</a>
+<p>A typedef of: long&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 21</a>
</p>
<p> A 64 bit signed integer type.
</p>
@@ -960,9 +960,9 @@ with a 64 bit alignment.
<span class='normal'>: Unsigned size type</span>
</h4>
<div class='jd-details-descr'>
-<p>A typedef of: uint64_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; When compiling for 64 bits.
+<p>A typedef of: uint64_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;When compiling for 64 bits.
</p>
-<p>A typedef of: uint32_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; When compiling for 32 bits.
+<p>A typedef of: uint32_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;When compiling for 32 bits.
</p>
<p> Unsigned size type. The number of bits depend on the compilation flags.
</p>
@@ -976,9 +976,9 @@ with a 64 bit alignment.
<span class='normal'>: Signed size type</span>
</h4>
<div class='jd-details-descr'>
-<p>A typedef of: int64_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; When compiling for 64 bits.
+<p>A typedef of: int64_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;When compiling for 64 bits.
</p>
-<p>A typedef of: int32_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; When compiling for 32 bits.
+<p>A typedef of: int32_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;When compiling for 32 bits.
</p>
<p> Signed size type. The number of bits depend on the compilation flags.
</p>
@@ -1128,9 +1128,9 @@ with a 128 bit alignment.
<span class='normal'>: 64 bit unsigned integer</span>
</h4>
<div class='jd-details-descr'>
-<p>A typedef of: unsigned long long&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Removed from <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 21 and higher</a>
+<p>A typedef of: unsigned long long&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Removed from <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 21 and higher</a>
</p>
-<p>A typedef of: unsigned long&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 21</a>
+<p>A typedef of: unsigned long&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Added in <a href='http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels'>API level 21</a>
</p>
<p> A 64 bit unsigned integer type.
</p>
diff --git a/docs/html/training/location/geofencing.jd b/docs/html/training/location/geofencing.jd
index 59fc4c665a53..556329cb1f7e 100644
--- a/docs/html/training/location/geofencing.jd
+++ b/docs/html/training/location/geofencing.jd
@@ -100,8 +100,8 @@ srcset="{@docRoot}images/training/geofence.png 1x, {@docRoot}images/training/geo
<h3>Create geofence objects</h3>
<p>
- First, use <code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.Builder.
- html">Geofence.Builder</a></code> to create a geofence, setting the desired radius, duration, and
+ First, use <code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.Builder.html">
+ Geofence.Builder</a></code> to create a geofence, setting the desired radius, duration, and
transition types for the geofence. For example, to populate a list object named
{@code mGeofenceList}:
</p>
diff --git a/drm/jni/android_drm_DrmManagerClient.cpp b/drm/jni/android_drm_DrmManagerClient.cpp
index 52597e10609a..63fe8acedd54 100644
--- a/drm/jni/android_drm_DrmManagerClient.cpp
+++ b/drm/jni/android_drm_DrmManagerClient.cpp
@@ -702,7 +702,7 @@ static jobject android_drm_DrmManagerClient_closeConvertSession(
return status;
}
-static JNINativeMethod nativeMethods[] = {
+static const JNINativeMethod nativeMethods[] = {
{"_initialize", "()I",
(void*)android_drm_DrmManagerClient_initialize},
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index abb51dbac1b3..1857345968fd 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -217,7 +217,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
}
@Override
- protected boolean onLevelChange(float level) {
+ protected boolean onLevelChange(int level) {
return mAnimatedVectorState.mVectorDrawable.setLevel(level);
}
diff --git a/graphics/java/android/graphics/drawable/ClipDrawable.java b/graphics/java/android/graphics/drawable/ClipDrawable.java
index 3b9250795992..31fccd0880c9 100644
--- a/graphics/java/android/graphics/drawable/ClipDrawable.java
+++ b/graphics/java/android/graphics/drawable/ClipDrawable.java
@@ -52,6 +52,8 @@ public class ClipDrawable extends DrawableWrapper {
public static final int HORIZONTAL = 1;
public static final int VERTICAL = 2;
+ private static final int MAX_LEVEL = 10000;
+
private final Rect mTmpRect = new Rect();
private ClipState mState;
@@ -141,7 +143,7 @@ public class ClipDrawable extends DrawableWrapper {
}
@Override
- protected boolean onLevelChange(float level) {
+ protected boolean onLevelChange(int level) {
super.onLevelChange(level);
invalidateSelf();
return true;
@@ -151,12 +153,12 @@ public class ClipDrawable extends DrawableWrapper {
public int getOpacity() {
final Drawable dr = getDrawable();
final int opacity = dr.getOpacity();
- if (opacity == PixelFormat.TRANSPARENT || dr.getLevelFloat() == 0) {
+ if (opacity == PixelFormat.TRANSPARENT || dr.getLevel() == 0) {
return PixelFormat.TRANSPARENT;
}
- final float level = getLevelFloat();
- if (level >= MAX_LEVEL_FLOAT) {
+ final int level = getLevel();
+ if (level >= MAX_LEVEL) {
return dr.getOpacity();
}
@@ -167,24 +169,24 @@ public class ClipDrawable extends DrawableWrapper {
@Override
public void draw(Canvas canvas) {
final Drawable dr = getDrawable();
- if (dr.getLevelFloat() == 0) {
+ if (dr.getLevel() == 0) {
return;
}
final Rect r = mTmpRect;
final Rect bounds = getBounds();
- final float level = getLevelFloat();
+ final int level = getLevel();
int w = bounds.width();
- final int iw = 0;
+ final int iw = 0; //mState.mDrawable.getIntrinsicWidth();
if ((mState.mOrientation & HORIZONTAL) != 0) {
- w -= Math.round((w - iw) * (MAX_LEVEL_FLOAT - level) / MAX_LEVEL_FLOAT);
+ w -= (w - iw) * (MAX_LEVEL - level) / MAX_LEVEL;
}
int h = bounds.height();
- final int ih = 0;
+ final int ih = 0; //mState.mDrawable.getIntrinsicHeight();
if ((mState.mOrientation & VERTICAL) != 0) {
- h -= Math.round((h - ih) * (MAX_LEVEL_FLOAT - level) / MAX_LEVEL_FLOAT);
+ h -= (h - ih) * (MAX_LEVEL - level) / MAX_LEVEL;
}
final int layoutDirection = getLayoutDirection();
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index fb7715507103..b95c183642ca 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -41,7 +41,6 @@ import android.graphics.Xfermode;
import android.os.Trace;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
-import android.util.FloatProperty;
import android.util.StateSet;
import android.util.TypedValue;
import android.util.Xml;
@@ -127,19 +126,12 @@ import java.util.Collection;
* document.</p></div>
*/
public abstract class Drawable {
-
private static final Rect ZERO_BOUNDS_RECT = new Rect();
static final PorterDuff.Mode DEFAULT_TINT_MODE = PorterDuff.Mode.SRC_IN;
- /** The standard maximum value for calls to {@link #setLevel(int)}. */
- public static final int MAX_LEVEL = 10000;
-
- /** The standard maximum value for calls to {@link #setLevel(float)}. */
- public static final float MAX_LEVEL_FLOAT = 10000.0f;
-
private int[] mStateSet = StateSet.WILD_CARD;
- private float mLevel = 0.0f;
+ private int mLevel = 0;
private int mChangingConfigurations = 0;
private Rect mBounds = ZERO_BOUNDS_RECT; // lazily becomes a new Rect()
private WeakReference<Callback> mCallback = null;
@@ -719,63 +711,22 @@ public abstract class Drawable {
}
/**
- * Sets the level for the drawable as an integer value where typically the
- * minimum level is 0 and the maximum is 10000 {@link #MAX_LEVEL}; however,
- * the range may vary based on the Drawable implementation and is not
- * clamped.
- * <p>
- * This allows a drawable to vary its imagery based on a continuous
- * controller. For example, it may be used to show progress or volume
- * level.
- * <p>
- * Use #setLevelFloat(float) to set the level as a high-precision
- * floating-point value.
+ * Specify the level for the drawable. This allows a drawable to vary its
+ * imagery based on a continuous controller, for example to show progress
+ * or volume level.
*
- * @param level the new level, typically between 0 and 10000
- * @return {@code true} if this change in level has caused the appearance
- * of the drawable to change and will require a subsequent call to
- * invalidate, {@code false} otherwise
- * @see #getLevel()
- * @see #setLevel(float)
- * @see #onLevelChange(int)
- */
- public final boolean setLevel(int level) {
- return setLevel((float) level);
- }
-
- /**
- * Returns the current level as a rounded integer value.
- * <p>
- * Use #getLevelFloat() to return the level as a high-precision
- * floating-point value.
+ * <p>If the new level you are supplying causes the appearance of the
+ * Drawable to change, then it is responsible for calling
+ * {@link #invalidateSelf} in order to have itself redrawn, <em>and</em>
+ * true will be returned from this function.
+ *
+ * @param level The new level, from 0 (minimum) to 10000 (maximum).
*
- * @return the current level, typically between 0 and 10000
- * @see #setLevel(int)
- * @see #getLevelFloat()
+ * @return Returns true if this change in level has caused the appearance
+ * of the Drawable to change (hence requiring an invalidate), otherwise
+ * returns false.
*/
- public final int getLevel() {
- return Math.round(mLevel);
- }
-
- /**
- * Sets the level for the drawable as a floating-point value where
- * typically the minimum level is 0.0 and the maximum is 10000.0
- * {@link #MAX_LEVEL_FLOAT}; however, the range may vary based on the
- * Drawable implementation and is not clamped.
- * <p>
- * This allows a drawable to vary its imagery based on a continuous
- * controller. For example, it may be used to show progress or volume
- * level.
- *
- * @param level the new level, typically between 0.0 and 10000.0
- * ({@link #MAX_LEVEL_FLOAT})
- * @return {@code true} if this change in level has caused the appearance
- * of the drawable to change and will require a subsequent call to
- * invalidate, {@code false} otherwise
- * @see #getLevelFloat()
- * @see #onLevelChange(float)
- */
- public final boolean setLevel(float level) {
+ public final boolean setLevel(int level) {
if (mLevel != level) {
mLevel = level;
return onLevelChange(level);
@@ -784,13 +735,11 @@ public abstract class Drawable {
}
/**
- * Returns the current level as a floating-point value.
+ * Retrieve the current level.
*
- * @return the current level, typically between 0.0 and 10000.0
- * ({@link #MAX_LEVEL_FLOAT})
- * @see #setLevel(float)
+ * @return int Current level, from 0 (minimum) to 10000 (maximum).
*/
- public final float getLevelFloat() {
+ public final int getLevel() {
return mLevel;
}
@@ -945,47 +894,14 @@ public abstract class Drawable {
* last state.
*/
protected boolean onStateChange(int[] state) { return false; }
-
- /**
- * Called when the drawable level changes.
- * <p>
- * Override this in your subclass to change appearance if you vary based on
- * level and do not need floating-point accuracy. To handle changes with
- * higher accuracy, override {@link #onLevelChange(float)} instead.
- * <p>
- * <strong>Note:</strong> Do not override both this method and
- * {@link #onLevelChange(float)}. Only override one method.
- *
- * @param level the level as an integer value, typically between 0
- * (minimum) and 10000 ({@link #MAX_LEVEL})
- * @return {@code true} if the level change has caused the appearance of
- * the drawable to change such that it needs to be redrawn, or
- * {@code false} if there is no need to redraw
+ /** Override this in your subclass to change appearance if you vary based
+ * on level.
+ * @return Returns true if the level change has caused the appearance of
+ * the Drawable to change (that is, it needs to be drawn), else false
+ * if it looks the same and there is no need to redraw it since its
+ * last level.
*/
protected boolean onLevelChange(int level) { return false; }
-
- /**
- * Called when the drawable level changes.
- * <p>
- * Override this in your subclass to change appearance if you vary based on
- * level and need floating-point accuracy.
- * <p>
- * <strong>Note:</strong> Do not override both this method and
- * {@link #onLevelChange(int)}. Only override one method. If your app
- * targets SDK <= 23 ({@link android.os.Build.VERSION_CODES#M M}), you
- * will need to override {@link #onLevelChange(int)} to receive callbacks
- * on devices running Android M and below.
- *
- * @param level the level as a floating-point value, typically between 0.0
- * and 10000.0 ({@link #MAX_LEVEL_FLOAT})
- * @return {@code true} if the level change has caused the appearance of
- * the drawable to change such that it needs to be redrawn, or
- * {@code false} if there is no need to redraw
- */
- protected boolean onLevelChange(float level) {
- return onLevelChange(Math.round(level));
- }
-
/**
* Override this in your subclass to change appearance if you vary based on
* the bounds.
@@ -1412,23 +1328,6 @@ public abstract class Drawable {
}
/**
- * Animatable property for Drawable level.
- *
- * @hide Until Drawable animations have been cleaned up.
- */
- public static final FloatProperty<Drawable> LEVEL = new FloatProperty<Drawable>("levelFloat") {
- @Override
- public Float get(Drawable object) {
- return object.getLevelFloat();
- }
-
- @Override
- public void setValue(Drawable object, float value) {
- object.setLevel(value);
- }
- };
-
- /**
* Obtains styled attributes from the theme, if available, or unstyled
* resources if the theme is null.
*/
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index 0210ddb191ce..1f7d9969c021 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -322,7 +322,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback {
}
@Override
- protected boolean onLevelChange(float level) {
+ protected boolean onLevelChange(int level) {
if (mLastDrawable != null) {
return mLastDrawable.setLevel(level);
}
@@ -420,14 +420,23 @@ public class DrawableContainer extends Drawable implements Drawable.Callback {
return mCurIndex;
}
- public boolean selectDrawable(int idx) {
- if (idx == mCurIndex) {
+ /**
+ * Sets the currently displayed drawable by index.
+ * <p>
+ * If an invalid index is specified, the current drawable will be set to
+ * {@code null} and the index will be set to {@code -1}.
+ *
+ * @param index the index of the drawable to display
+ * @return {@code true} if the drawable changed, {@code false} otherwise
+ */
+ public boolean selectDrawable(int index) {
+ if (index == mCurIndex) {
return false;
}
final long now = SystemClock.uptimeMillis();
- if (DEBUG) android.util.Log.i(TAG, toString() + " from " + mCurIndex + " to " + idx
+ if (DEBUG) android.util.Log.i(TAG, toString() + " from " + mCurIndex + " to " + index
+ ": exit=" + mDrawableContainerState.mExitFadeDuration
+ " enter=" + mDrawableContainerState.mEnterFadeDuration);
@@ -448,10 +457,10 @@ public class DrawableContainer extends Drawable implements Drawable.Callback {
mCurrDrawable.setVisible(false, false);
}
- if (idx >= 0 && idx < mDrawableContainerState.mNumChildren) {
- final Drawable d = mDrawableContainerState.getChild(idx);
+ if (index >= 0 && index < mDrawableContainerState.mNumChildren) {
+ final Drawable d = mDrawableContainerState.getChild(index);
mCurrDrawable = d;
- mCurIndex = idx;
+ mCurIndex = index;
if (d != null) {
if (mDrawableContainerState.mEnterFadeDuration > 0) {
mEnterAnimationEnd = now + mDrawableContainerState.mEnterFadeDuration;
@@ -510,7 +519,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback {
d.setVisible(isVisible(), true);
d.setDither(mDrawableContainerState.mDither);
d.setState(getState());
- d.setLevel(getLevelFloat());
+ d.setLevel(getLevel());
d.setBounds(getBounds());
d.setLayoutDirection(getLayoutDirection());
d.setAutoMirrored(mDrawableContainerState.mAutoMirrored);
diff --git a/graphics/java/android/graphics/drawable/DrawableWrapper.java b/graphics/java/android/graphics/drawable/DrawableWrapper.java
index 57b4db244c56..9185e1a06466 100644
--- a/graphics/java/android/graphics/drawable/DrawableWrapper.java
+++ b/graphics/java/android/graphics/drawable/DrawableWrapper.java
@@ -92,7 +92,7 @@ public abstract class DrawableWrapper extends Drawable implements Drawable.Callb
// Only call setters for data that's stored in the base Drawable.
dr.setVisible(isVisible(), true);
dr.setState(getState());
- dr.setLevel(getLevelFloat());
+ dr.setLevel(getLevel());
dr.setBounds(getBounds());
dr.setLayoutDirection(getLayoutDirection());
@@ -286,7 +286,7 @@ public abstract class DrawableWrapper extends Drawable implements Drawable.Callb
}
@Override
- protected boolean onLevelChange(float level) {
+ protected boolean onLevelChange(int level) {
return mDrawable != null && mDrawable.setLevel(level);
}
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index 15295a03abd7..d7fd8a55d404 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -530,8 +530,8 @@ public class GradientDrawable extends Drawable {
* {@code false} otherwise
*
* @see #mutate()
- * @see #setLevel(float)
- * @see #getLevelFloat()
+ * @see #setLevel(int)
+ * @see #getLevel()
* @see #isUseLevel()
*/
public void setUseLevel(boolean useLevel) {
@@ -764,7 +764,7 @@ public class GradientDrawable extends Drawable {
if (mRingPath != null && (!st.mUseLevelForShape || !mPathIsDirty)) return mRingPath;
mPathIsDirty = false;
- float sweep = st.mUseLevelForShape ? (360.0f * getLevelFloat() / MAX_LEVEL_FLOAT) : 360f;
+ float sweep = st.mUseLevelForShape ? (360.0f * getLevel() / 10000.0f) : 360f;
RectF bounds = new RectF(mRect);
@@ -990,7 +990,7 @@ public class GradientDrawable extends Drawable {
}
@Override
- protected boolean onLevelChange(float level) {
+ protected boolean onLevelChange(int level) {
super.onLevelChange(level);
mGradientIsDirty = true;
mPathIsDirty = true;
@@ -1026,7 +1026,7 @@ public class GradientDrawable extends Drawable {
final float x0, x1, y0, y1;
if (st.mGradient == LINEAR_GRADIENT) {
- final float level = st.mUseLevel ? getLevelFloat() / MAX_LEVEL_FLOAT : 1.0f;
+ final float level = st.mUseLevel ? getLevel() / 10000.0f : 1.0f;
switch (st.mOrientation) {
case TOP_BOTTOM:
x0 = r.left; y0 = r.top;
@@ -1080,7 +1080,7 @@ public class GradientDrawable extends Drawable {
}
if (st.mUseLevel) {
- radius *= getLevelFloat() / MAX_LEVEL_FLOAT;
+ radius *= getLevel() / 10000.0f;
}
mGradientRadius = radius;
@@ -1115,7 +1115,7 @@ public class GradientDrawable extends Drawable {
tempPositions = st.mTempPositions = new float[length + 1];
}
- final float level = getLevelFloat() / MAX_LEVEL_FLOAT;
+ final float level = getLevel() / 10000.0f;
for (int i = 0; i < length; i++) {
tempPositions[i] = i * fraction * level;
}
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index c9e38b9841eb..1a0ba6f2eabc 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -1400,7 +1400,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
}
@Override
- protected boolean onLevelChange(float level) {
+ protected boolean onLevelChange(int level) {
boolean changed = false;
final ChildDrawable[] array = mLayerState.mChildren;
@@ -1733,7 +1733,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
clone.setCallback(owner);
clone.setLayoutDirection(dr.getLayoutDirection());
clone.setBounds(dr.getBounds());
- clone.setLevel(dr.getLevelFloat());
+ clone.setLevel(dr.getLevel());
} else {
clone = null;
}
diff --git a/graphics/java/android/graphics/drawable/LevelListDrawable.java b/graphics/java/android/graphics/drawable/LevelListDrawable.java
index 09d8b6fdb1e6..b01c643a2a01 100644
--- a/graphics/java/android/graphics/drawable/LevelListDrawable.java
+++ b/graphics/java/android/graphics/drawable/LevelListDrawable.java
@@ -69,16 +69,15 @@ public class LevelListDrawable extends DrawableContainer {
if (drawable != null) {
mLevelListState.addLevel(low, high, drawable);
// in case the new state matches our current state...
- onLevelChange(getLevelFloat());
+ onLevelChange(getLevel());
}
}
// overrides from Drawable
@Override
- protected boolean onLevelChange(float level) {
- final int nearestLevel = Math.round(level);
- final int idx = mLevelListState.indexOfLevel(nearestLevel);
+ protected boolean onLevelChange(int level) {
+ int idx = mLevelListState.indexOfLevel(level);
if (selectDrawable(idx)) {
return true;
}
@@ -142,7 +141,7 @@ public class LevelListDrawable extends DrawableContainer {
mLevelListState.addLevel(low, high, dr);
}
- onLevelChange(getLevelFloat());
+ onLevelChange(getLevel());
}
@Override
@@ -241,7 +240,7 @@ public class LevelListDrawable extends DrawableContainer {
private LevelListDrawable(LevelListState state, Resources res) {
final LevelListState as = new LevelListState(state, this, res);
setConstantState(as);
- onLevelChange(getLevelFloat());
+ onLevelChange(getLevel());
}
}
diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java
index 71c9977ba190..036a078eb00d 100644
--- a/graphics/java/android/graphics/drawable/RotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/RotateDrawable.java
@@ -303,10 +303,10 @@ public class RotateDrawable extends DrawableWrapper {
}
@Override
- protected boolean onLevelChange(float level) {
+ protected boolean onLevelChange(int level) {
super.onLevelChange(level);
- final float value = level / (float) MAX_LEVEL_FLOAT;
+ final float value = level / (float) MAX_LEVEL;
final float degrees = MathUtils.lerp(mState.mFromDegrees, mState.mToDegrees, value);
mState.mCurrentDegrees = degrees;
diff --git a/graphics/java/android/graphics/drawable/ScaleDrawable.java b/graphics/java/android/graphics/drawable/ScaleDrawable.java
index 38c6b8093c1a..f9206b7d3c26 100644
--- a/graphics/java/android/graphics/drawable/ScaleDrawable.java
+++ b/graphics/java/android/graphics/drawable/ScaleDrawable.java
@@ -35,21 +35,33 @@ import java.io.IOException;
/**
* A Drawable that changes the size of another Drawable based on its current
- * level value. You can control how much the child Drawable changes in width
+ * level value. You can control how much the child Drawable changes in width
* and height based on the level, as well as a gravity to control where it is
- * placed in its overall container. Most often used to implement things like
+ * placed in its overall container. Most often used to implement things like
* progress bars.
- *
- * <p>It can be defined in an XML file with the <code>&lt;scale></code> element. For more
- * information, see the guide to <a
- * href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.</p>
+ * <p>
+ * The default level may be specified from XML using the
+ * {@link android.R.styleable#ScaleDrawable_level android:level} property. When
+ * this property is not specified, the default level is 0, which corresponds to
+ * zero height and/or width depending on the values specified for
+ * {@code android.R.styleable#ScaleDrawable_scaleWidth scaleWidth} and
+ * {@code android.R.styleable#ScaleDrawable_scaleHeight scaleHeight}. At run
+ * time, the level may be set via {@link #setLevel(int)}.
+ * <p>
+ * A scale drawable may be defined in an XML file with the {@code &lt;scale>}
+ * element. For more information, see the guide to
+ * <a href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable
+ * Resources</a>.
*
* @attr ref android.R.styleable#ScaleDrawable_scaleWidth
* @attr ref android.R.styleable#ScaleDrawable_scaleHeight
* @attr ref android.R.styleable#ScaleDrawable_scaleGravity
* @attr ref android.R.styleable#ScaleDrawable_drawable
+ * @attr ref android.R.styleable#ScaleDrawable_level
*/
public class ScaleDrawable extends DrawableWrapper {
+ private static final int MAX_LEVEL = 10000;
+
private final Rect mTmpRect = new Rect();
private ScaleState mState;
@@ -90,6 +102,8 @@ public class ScaleDrawable extends DrawableWrapper {
inflateChildDrawable(r, parser, attrs, theme);
verifyRequiredAttributes(a);
a.recycle();
+
+ updateLocalState();
}
private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException {
@@ -115,6 +129,8 @@ public class ScaleDrawable extends DrawableWrapper {
R.styleable.ScaleDrawable_scaleGravity, state.mGravity);
state.mUseIntrinsicSizeAsMin = a.getBoolean(
R.styleable.ScaleDrawable_useIntrinsicSizeAsMinimum, state.mUseIntrinsicSizeAsMin);
+ state.mInitialLevel = a.getInt(
+ R.styleable.ScaleDrawable_level, state.mInitialLevel);
final Drawable dr = a.getDrawable(R.styleable.ScaleDrawable_drawable);
if (dr != null) {
@@ -163,12 +179,14 @@ public class ScaleDrawable extends DrawableWrapper {
// The drawable may have changed as a result of applying the theme, so
// apply the theme to the wrapped drawable last.
super.applyTheme(t);
+
+ updateLocalState();
}
@Override
public void draw(Canvas canvas) {
final Drawable d = getDrawable();
- if (d != null && d.getLevelFloat() != 0) {
+ if (d != null && d.getLevel() != 0) {
d.draw(canvas);
}
}
@@ -176,12 +194,12 @@ public class ScaleDrawable extends DrawableWrapper {
@Override
public int getOpacity() {
final Drawable d = getDrawable();
- if (d.getLevelFloat() == 0) {
+ if (d.getLevel() == 0) {
return PixelFormat.TRANSPARENT;
}
final int opacity = d.getOpacity();
- if (opacity == PixelFormat.OPAQUE && d.getLevelFloat() < MAX_LEVEL_FLOAT) {
+ if (opacity == PixelFormat.OPAQUE && d.getLevel() < MAX_LEVEL) {
return PixelFormat.TRANSLUCENT;
}
@@ -189,7 +207,7 @@ public class ScaleDrawable extends DrawableWrapper {
}
@Override
- protected boolean onLevelChange(float level) {
+ protected boolean onLevelChange(int level) {
super.onLevelChange(level);
onBoundsChange(getBounds());
invalidateSelf();
@@ -201,20 +219,18 @@ public class ScaleDrawable extends DrawableWrapper {
final Drawable d = getDrawable();
final Rect r = mTmpRect;
final boolean min = mState.mUseIntrinsicSizeAsMin;
- final float level = getLevelFloat();
+ final int level = getLevel();
int w = bounds.width();
if (mState.mScaleWidth > 0) {
final int iw = min ? d.getIntrinsicWidth() : 0;
- w -= (int) ((w - iw) * (MAX_LEVEL_FLOAT - level)
- * mState.mScaleWidth / MAX_LEVEL_FLOAT);
+ w -= (int) ((w - iw) * (MAX_LEVEL - level) * mState.mScaleWidth / MAX_LEVEL);
}
int h = bounds.height();
if (mState.mScaleHeight > 0) {
final int ih = min ? d.getIntrinsicHeight() : 0;
- h -= (int) ((h - ih) * (MAX_LEVEL_FLOAT - level)
- * mState.mScaleHeight / MAX_LEVEL_FLOAT);
+ h -= (int) ((h - ih) * (MAX_LEVEL - level) * mState.mScaleHeight / MAX_LEVEL);
}
final int layoutDirection = getLayoutDirection();
@@ -239,6 +255,7 @@ public class ScaleDrawable extends DrawableWrapper {
float mScaleHeight = DO_NOT_SCALE;
int mGravity = Gravity.LEFT;
boolean mUseIntrinsicSizeAsMin = false;
+ int mInitialLevel = 0;
ScaleState(ScaleState orig) {
super(orig);
@@ -248,6 +265,7 @@ public class ScaleDrawable extends DrawableWrapper {
mScaleHeight = orig.mScaleHeight;
mGravity = orig.mGravity;
mUseIntrinsicSizeAsMin = orig.mUseIntrinsicSizeAsMin;
+ mInitialLevel = orig.mInitialLevel;
}
}
@@ -257,10 +275,23 @@ public class ScaleDrawable extends DrawableWrapper {
}
}
+ /**
+ * Creates a new ScaleDrawable based on the specified constant state.
+ * <p>
+ * The resulting drawable is guaranteed to have a new constant state.
+ *
+ * @param state constant state from which the drawable inherits
+ */
private ScaleDrawable(ScaleState state, Resources res) {
super(state, res);
mState = state;
+
+ updateLocalState();
+ }
+
+ private void updateLocalState() {
+ setLevel(mState.mInitialLevel);
}
}
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index 174722538014..1105ca4b6cbc 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -126,9 +126,13 @@ import java.util.Stack;
* <dd>Defines path data using exactly same format as "d" attribute
* in the SVG's path data. This is defined in the viewport space.</dd>
* <dt><code>android:fillColor</code></dt>
- * <dd>Defines the color to fill the path (none if not present).</dd>
+ * <dd>Specifies the color used to fill the path. May be a color or (SDK 24+ only) a color state
+ * list. If this property is animated, any value set by the animation will override the original
+ * value. No path fill is drawn if this property is not specified.</dd>
* <dt><code>android:strokeColor</code></dt>
- * <dd>Defines the color to draw the path outline (none if not present).</dd>
+ * <dd>Specifies the color used to draw the path outline. May be a color or (SDK 24+ only) a color
+ * state list. If this property is animated, any value set by the animation will override the
+ * original value. No path outline is drawn if this property is not specified.</dd>
* <dt><code>android:strokeWidth</code></dt>
* <dd>The width a path stroke.</dd>
* <dt><code>android:strokeAlpha</code></dt>
@@ -374,19 +378,24 @@ public class VectorDrawable extends Drawable {
@Override
public boolean isStateful() {
- return super.isStateful() || (mVectorState != null && mVectorState.mTint != null
- && mVectorState.mTint.isStateful());
+ return super.isStateful() || (mVectorState != null && mVectorState.isStateful());
}
@Override
protected boolean onStateChange(int[] stateSet) {
+ boolean changed = false;
+
final VectorDrawableState state = mVectorState;
+ if (state.mVPathRenderer != null && state.mVPathRenderer.onStateChange(stateSet)) {
+ changed = true;
+ state.mCacheDirty = true;
+ }
if (state.mTint != null && state.mTintMode != null) {
mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
- invalidateSelf();
- return true;
+ changed = true;
}
- return false;
+
+ return changed;
}
@Override
@@ -664,7 +673,7 @@ public class VectorDrawable extends Drawable {
if (SHAPE_PATH.equals(tagName)) {
final VFullPath path = new VFullPath();
path.inflate(res, attrs, theme);
- currentGroup.mChildren.add(path);
+ currentGroup.addChild(path);
if (path.getPathName() != null) {
pathRenderer.mVGTargetsMap.put(path.getPathName(), path);
}
@@ -673,7 +682,7 @@ public class VectorDrawable extends Drawable {
} else if (SHAPE_CLIP_PATH.equals(tagName)) {
final VClipPath path = new VClipPath();
path.inflate(res, attrs, theme);
- currentGroup.mChildren.add(path);
+ currentGroup.addChild(path);
if (path.getPathName() != null) {
pathRenderer.mVGTargetsMap.put(path.getPathName(), path);
}
@@ -681,7 +690,7 @@ public class VectorDrawable extends Drawable {
} else if (SHAPE_GROUP.equals(tagName)) {
VGroup newChildGroup = new VGroup();
newChildGroup.inflate(res, attrs, theme);
- currentGroup.mChildren.add(newChildGroup);
+ currentGroup.addChild(newChildGroup);
groupStack.push(newChildGroup);
if (newChildGroup.getGroupName() != null) {
pathRenderer.mVGTargetsMap.put(newChildGroup.getGroupName(),
@@ -700,7 +709,7 @@ public class VectorDrawable extends Drawable {
// Print the tree out for debug.
if (DBG_VECTOR_DRAWABLE) {
- printGroupTree(pathRenderer.mRootGroup, 0);
+ pathRenderer.printGroupTree();
}
if (noPathTag) {
@@ -715,24 +724,6 @@ public class VectorDrawable extends Drawable {
}
}
- private void printGroupTree(VGroup currentGroup, int level) {
- String indent = "";
- for (int i = 0; i < level; i++) {
- indent += " ";
- }
- // Print the current node
- Log.v(LOGTAG, indent + "current group is :" + currentGroup.getGroupName()
- + " rotation is " + currentGroup.mRotate);
- Log.v(LOGTAG, indent + "matrix is :" + currentGroup.getLocalMatrix().toString());
- // Then print all the children groups
- for (int i = 0; i < currentGroup.mChildren.size(); i++) {
- final VObject child = currentGroup.mChildren.get(i);
- if (child instanceof VGroup) {
- printGroupTree((VGroup) child, level + 1);
- }
- }
- }
-
@Override
public int getChangingConfigurations() {
return super.getChangingConfigurations() | mVectorState.getChangingConfigurations();
@@ -890,6 +881,11 @@ public class VectorDrawable extends Drawable {
return mChangingConfigurations
| (mTint != null ? mTint.getChangingConfigurations() : 0);
}
+
+ public boolean isStateful() {
+ return (mTint != null && mTint.isStateful())
+ || (mVPathRenderer != null && mVPathRenderer.isStateful());
+ }
}
private static class VPathRenderer {
@@ -972,21 +968,35 @@ public class VectorDrawable extends Drawable {
mRootGroup.applyTheme(t);
}
+ public boolean onStateChange(int[] stateSet) {
+ return mRootGroup.onStateChange(stateSet);
+ }
+
+ public boolean isStateful() {
+ return mRootGroup.isStateful();
+ }
+
public void draw(Canvas canvas, int w, int h, ColorFilter filter) {
final float scaleX = w / mViewportWidth;
final float scaleY = h / mViewportHeight;
mRootGroup.draw(canvas, mTempState, Matrix.IDENTITY_MATRIX, filter, scaleX, scaleY);
}
+
+ public void printGroupTree() {
+ mRootGroup.printGroupTree("");
+ }
}
private static class VGroup implements VObject {
+ private static final String GROUP_INDENT = " ";
+
// mStackedMatrix is only used temporarily when drawing, it combines all
// the parents' local matrices with the current one.
private final Matrix mStackedMatrix = new Matrix();
/////////////////////////////////////////////////////
// Variables below need to be copied (deep copy if applicable) for mutation.
- final ArrayList<VObject> mChildren = new ArrayList<>();
+ private final ArrayList<VObject> mChildren = new ArrayList<>();
private float mRotate = 0;
private float mPivotX = 0;
@@ -995,6 +1005,7 @@ public class VectorDrawable extends Drawable {
private float mScaleY = 1;
private float mTranslateX = 0;
private float mTranslateY = 0;
+ private boolean mIsStateful;
// mLocalMatrix is updated based on the update of transformation information,
// either parsed from the XML or by animation.
@@ -1011,6 +1022,7 @@ public class VectorDrawable extends Drawable {
mScaleY = copy.mScaleY;
mTranslateX = copy.mTranslateX;
mTranslateY = copy.mTranslateY;
+ mIsStateful = copy.mIsStateful;
mThemeAttrs = copy.mThemeAttrs;
mGroupName = copy.mGroupName;
mChangingConfigurations = copy.mChangingConfigurations;
@@ -1054,6 +1066,12 @@ public class VectorDrawable extends Drawable {
return mLocalMatrix;
}
+ public void addChild(VObject child) {
+ mChildren.add(child);
+
+ mIsStateful |= child.isStateful();
+ }
+
@Override
public void draw(Canvas canvas, TempState temp, Matrix currentMatrix,
ColorFilter filter, float scaleX, float scaleY) {
@@ -1109,6 +1127,26 @@ public class VectorDrawable extends Drawable {
}
@Override
+ public boolean onStateChange(int[] stateSet) {
+ boolean changed = false;
+
+ final ArrayList<VObject> children = mChildren;
+ for (int i = 0, count = children.size(); i < count; i++) {
+ final VObject child = children.get(i);
+ if (child.isStateful()) {
+ changed |= child.onStateChange(stateSet);
+ }
+ }
+
+ return changed;
+ }
+
+ @Override
+ public boolean isStateful() {
+ return mIsStateful;
+ }
+
+ @Override
public boolean canApplyTheme() {
if (mThemeAttrs != null) {
return true;
@@ -1139,6 +1177,9 @@ public class VectorDrawable extends Drawable {
final VObject child = children.get(i);
if (child.canApplyTheme()) {
child.applyTheme(t);
+
+ // Applying a theme may have made the child stateful.
+ mIsStateful |= child.isStateful();
}
}
}
@@ -1153,6 +1194,24 @@ public class VectorDrawable extends Drawable {
mLocalMatrix.postTranslate(mTranslateX + mPivotX, mTranslateY + mPivotY);
}
+ public void printGroupTree(String indent) {
+ Log.v(LOGTAG, indent + "group:" + getGroupName() + " rotation is " + mRotate);
+ Log.v(LOGTAG, indent + "matrix:" + getLocalMatrix().toString());
+
+ final int count = mChildren.size();
+ if (count > 0) {
+ indent += GROUP_INDENT;
+ }
+
+ // Then print all the children groups.
+ for (int i = 0; i < count; i++) {
+ final VObject child = mChildren.get(i);
+ if (child instanceof VGroup) {
+ ((VGroup) child).printGroupTree(indent);
+ }
+ }
+ }
+
/* Setters and Getters, used by animator from AnimatedVectorDrawable. */
@SuppressWarnings("unused")
public float getRotation() {
@@ -1398,6 +1457,16 @@ public class VectorDrawable extends Drawable {
// No-op.
}
+ @Override
+ public boolean onStateChange(int[] stateSet) {
+ return false;
+ }
+
+ @Override
+ public boolean isStateful() {
+ return false;
+ }
+
private void updateStateFromTypedArray(TypedArray a) {
// Account for any configuration changes.
mChangingConfigurations |= a.getChangingConfigurations();
@@ -1427,9 +1496,11 @@ public class VectorDrawable extends Drawable {
// Variables below need to be copied (deep copy if applicable) for mutation.
private int[] mThemeAttrs;
+ ColorStateList mStrokeColors = null;
int mStrokeColor = Color.TRANSPARENT;
float mStrokeWidth = 0;
+ ColorStateList mFillColors = null;
int mFillColor = Color.TRANSPARENT;
float mStrokeAlpha = 1.0f;
int mFillRule;
@@ -1448,11 +1519,14 @@ public class VectorDrawable extends Drawable {
public VFullPath(VFullPath copy) {
super(copy);
+
mThemeAttrs = copy.mThemeAttrs;
+ mStrokeColors = copy.mStrokeColors;
mStrokeColor = copy.mStrokeColor;
mStrokeWidth = copy.mStrokeWidth;
mStrokeAlpha = copy.mStrokeAlpha;
+ mFillColors = copy.mFillColors;
mFillColor = copy.mFillColor;
mFillRule = copy.mFillRule;
mFillAlpha = copy.mFillAlpha;
@@ -1492,6 +1566,31 @@ public class VectorDrawable extends Drawable {
}
@Override
+ public boolean onStateChange(int[] stateSet) {
+ boolean changed = false;
+
+ if (mStrokeColors != null && mStrokeColors.isStateful()) {
+ final int strokeColor = mStrokeColor;
+ mStrokeColor = mStrokeColors.getColorForState(stateSet, strokeColor);
+ changed |= strokeColor != mStrokeColor;
+ }
+
+ if (mFillColors != null && mFillColors.isStateful()) {
+ final int fillColor = mFillColor;
+ mFillColor = mFillColors.getColorForState(stateSet, fillColor);
+ changed |= fillColor != mFillColor;
+ }
+
+ return changed;
+ }
+
+ @Override
+ public boolean isStateful() {
+ return mStrokeColors != null && mStrokeColors.isStateful()
+ || mFillColors != null && mFillColors.isStateful();
+ }
+
+ @Override
public void toPath(TempState temp, Path path) {
super.toPath(temp, path);
@@ -1614,8 +1713,20 @@ public class VectorDrawable extends Drawable {
mNodes = PathParser.createNodesFromPathData(pathData);
}
- mFillColor = a.getColor(R.styleable.VectorDrawablePath_fillColor,
- mFillColor);
+ final ColorStateList fillColors = a.getColorStateList(
+ R.styleable.VectorDrawablePath_fillColor);
+ if (fillColors != null) {
+ mFillColors = fillColors;
+ mFillColor = fillColors.getDefaultColor();
+ }
+
+ final ColorStateList strokeColors = a.getColorStateList(
+ R.styleable.VectorDrawablePath_strokeColor);
+ if (strokeColors != null) {
+ mStrokeColors = strokeColors;
+ mStrokeColor = strokeColors.getDefaultColor();
+ }
+
mFillAlpha = a.getFloat(R.styleable.VectorDrawablePath_fillAlpha,
mFillAlpha);
mStrokeLineCap = getStrokeLineCap(a.getInt(
@@ -1624,8 +1735,6 @@ public class VectorDrawable extends Drawable {
R.styleable.VectorDrawablePath_strokeLineJoin, -1), mStrokeLineJoin);
mStrokeMiterlimit = a.getFloat(
R.styleable.VectorDrawablePath_strokeMiterLimit, mStrokeMiterlimit);
- mStrokeColor = a.getColor(R.styleable.VectorDrawablePath_strokeColor,
- mStrokeColor);
mStrokeAlpha = a.getFloat(R.styleable.VectorDrawablePath_strokeAlpha,
mStrokeAlpha);
mStrokeWidth = a.getFloat(R.styleable.VectorDrawablePath_strokeWidth,
@@ -1662,6 +1771,7 @@ public class VectorDrawable extends Drawable {
@SuppressWarnings("unused")
void setStrokeColor(int strokeColor) {
+ mStrokeColors = null;
mStrokeColor = strokeColor;
}
@@ -1692,6 +1802,7 @@ public class VectorDrawable extends Drawable {
@SuppressWarnings("unused")
void setFillColor(int fillColor) {
+ mFillColors = null;
mFillColor = fillColor;
}
@@ -1752,5 +1863,7 @@ public class VectorDrawable extends Drawable {
void inflate(Resources r, AttributeSet attrs, Theme theme);
boolean canApplyTheme();
void applyTheme(Theme t);
+ boolean onStateChange(int[] state);
+ boolean isStateful();
}
}
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 3eb13ab9a72d..cc0943f52fdb 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -24,6 +24,7 @@ hwui_src_files := \
utils/GLUtils.cpp \
utils/LinearAllocator.cpp \
utils/NinePatchImpl.cpp \
+ utils/StringUtils.cpp \
AmbientShadow.cpp \
AnimationContext.cpp \
Animator.cpp \
@@ -168,7 +169,8 @@ LOCAL_SRC_FILES += \
unit_tests/CanvasStateTests.cpp \
unit_tests/ClipAreaTests.cpp \
unit_tests/DamageAccumulatorTests.cpp \
- unit_tests/LinearAllocatorTests.cpp
+ unit_tests/LinearAllocatorTests.cpp \
+ unit_tests/StringUtilsTests.cpp
include $(BUILD_NATIVE_TEST)
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index ff713133e389..7c63e316ba38 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -54,7 +54,6 @@ Caches::Caches(RenderState& renderState)
, mInitialized(false) {
INIT_LOGD("Creating OpenGL renderer caches");
init();
- initFont();
initConstraints();
initStaticProperties();
initExtensions();
@@ -78,10 +77,6 @@ bool Caches::init() {
return true;
}
-void Caches::initFont() {
- fontRenderer = GammaFontRenderer::createRenderer();
-}
-
void Caches::initExtensions() {
if (mExtensions.hasDebugMarker()) {
eventMark = glInsertEventMarkerEXT;
@@ -100,15 +95,9 @@ void Caches::initConstraints() {
}
void Caches::initStaticProperties() {
- gpuPixelBuffersEnabled = false;
-
// OpenGL ES 3.0+ specific features
- if (mExtensions.hasPixelBufferObjects()) {
- char property[PROPERTY_VALUE_MAX];
- if (property_get(PROPERTY_ENABLE_GPU_PIXEL_BUFFERS, property, "true") > 0) {
- gpuPixelBuffersEnabled = !strcmp(property, "true");
- }
- }
+ gpuPixelBuffersEnabled = mExtensions.hasPixelBufferObjects()
+ && property_get_bool(PROPERTY_ENABLE_GPU_PIXEL_BUFFERS, true);
}
void Caches::terminate() {
@@ -203,14 +192,14 @@ void Caches::dumpMemoryUsage(String8 &log) {
dropShadowCache.getMaxSize());
log.appendFormat(" PatchCache %8d / %8d\n",
patchCache.getSize(), patchCache.getMaxSize());
- for (uint32_t i = 0; i < fontRenderer->getFontRendererCount(); i++) {
- const uint32_t sizeA8 = fontRenderer->getFontRendererSize(i, GL_ALPHA);
- const uint32_t sizeRGBA = fontRenderer->getFontRendererSize(i, GL_RGBA);
- log.appendFormat(" FontRenderer %d A8 %8d / %8d\n", i, sizeA8, sizeA8);
- log.appendFormat(" FontRenderer %d RGBA %8d / %8d\n", i, sizeRGBA, sizeRGBA);
- log.appendFormat(" FontRenderer %d total %8d / %8d\n", i, sizeA8 + sizeRGBA,
- sizeA8 + sizeRGBA);
- }
+
+ const uint32_t sizeA8 = fontRenderer.getFontRendererSize(GL_ALPHA);
+ const uint32_t sizeRGBA = fontRenderer.getFontRendererSize(GL_RGBA);
+ log.appendFormat(" FontRenderer A8 %8d / %8d\n", sizeA8, sizeA8);
+ log.appendFormat(" FontRenderer RGBA %8d / %8d\n", sizeRGBA, sizeRGBA);
+ log.appendFormat(" FontRenderer total %8d / %8d\n", sizeA8 + sizeRGBA,
+ sizeA8 + sizeRGBA);
+
log.appendFormat("Other:\n");
log.appendFormat(" FboCache %8d / %8d\n",
fboCache.getSize(), fboCache.getMaxSize());
@@ -222,10 +211,8 @@ void Caches::dumpMemoryUsage(String8 &log) {
total += tessellationCache.getSize();
total += dropShadowCache.getSize();
total += patchCache.getSize();
- for (uint32_t i = 0; i < fontRenderer->getFontRendererCount(); i++) {
- total += fontRenderer->getFontRendererSize(i, GL_ALPHA);
- total += fontRenderer->getFontRendererSize(i, GL_RGBA);
- }
+ total += fontRenderer.getFontRendererSize(GL_ALPHA);
+ total += fontRenderer.getFontRendererSize(GL_RGBA);
log.appendFormat("Total memory usage:\n");
log.appendFormat(" %d bytes, %.2f MB\n", total, total / 1024.0f / 1024.0f);
@@ -250,12 +237,12 @@ void Caches::flush(FlushMode mode) {
patchCache.clear();
dropShadowCache.clear();
gradientCache.clear();
- fontRenderer->clear();
+ fontRenderer.clear();
fboCache.clear();
dither.clear();
// fall through
case FlushMode::Moderate:
- fontRenderer->flush();
+ fontRenderer.flush();
textureCache.flush();
pathCache.clear();
tessellationCache.clear();
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 929db17a22a8..61e958d42148 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -21,6 +21,7 @@
#include "Dither.h"
#include "Extensions.h"
#include "FboCache.h"
+#include "GammaFontRenderer.h"
#include "GradientCache.h"
#include "LayerCache.h"
#include "PatchCache.h"
@@ -53,8 +54,6 @@
namespace android {
namespace uirenderer {
-class GammaFontRenderer;
-
///////////////////////////////////////////////////////////////////////////////
// Caches
///////////////////////////////////////////////////////////////////////////////
@@ -156,7 +155,7 @@ public:
TextDropShadowCache dropShadowCache;
FboCache fboCache;
- GammaFontRenderer* fontRenderer;
+ GammaFontRenderer fontRenderer;
TaskManager tasks;
@@ -178,8 +177,6 @@ public:
TextureState& textureState() { return *mTextureState; }
private:
-
- void initFont();
void initExtensions();
void initConstraints();
void initStaticProperties();
diff --git a/libs/hwui/Debug.h b/libs/hwui/Debug.h
index 5808aaca76be..e98fa0440591 100644
--- a/libs/hwui/Debug.h
+++ b/libs/hwui/Debug.h
@@ -20,9 +20,6 @@
// Turn on to check for OpenGL errors on each frame
#define DEBUG_OPENGL 1
-// Turn on to display informations about the GPU
-#define DEBUG_EXTENSIONS 0
-
// Turn on to enable initialization information
#define DEBUG_INIT 0
diff --git a/libs/hwui/DeferredDisplayList.cpp b/libs/hwui/DeferredDisplayList.cpp
index 9fb1e756c00d..a81ffb9f59fa 100644
--- a/libs/hwui/DeferredDisplayList.cpp
+++ b/libs/hwui/DeferredDisplayList.cpp
@@ -631,7 +631,7 @@ static void replayBatchList(const std::vector<Batch*>& batchList,
void DeferredDisplayList::flush(OpenGLRenderer& renderer, Rect& dirty) {
ATRACE_NAME("flush drawing commands");
- Caches::getInstance().fontRenderer->endPrecaching();
+ Caches::getInstance().fontRenderer.endPrecaching();
if (isEmpty()) return; // nothing to flush
renderer.restoreToCount(1);
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index 14126a9e31a7..dc5cb8b349f1 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -1246,7 +1246,7 @@ public:
virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
const DeferredDisplayState& state) override {
- FontRenderer& fontRenderer = renderer.getCaches().fontRenderer->getFontRenderer(mPaint);
+ FontRenderer& fontRenderer = renderer.getCaches().fontRenderer.getFontRenderer();
fontRenderer.precache(mPaint, mText, mCount, SkMatrix::I());
deferInfo.batchId = mPaint->getColor() == SK_ColorBLACK ?
@@ -1311,7 +1311,7 @@ public:
virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
const DeferredDisplayState& state) override {
- FontRenderer& fontRenderer = renderer.getCaches().fontRenderer->getFontRenderer(mPaint);
+ FontRenderer& fontRenderer = renderer.getCaches().fontRenderer.getFontRenderer();
SkMatrix transform;
renderer.findBestFontTransform(state.mMatrix, &transform);
if (mPrecacheTransform != transform) {
diff --git a/libs/hwui/Extensions.cpp b/libs/hwui/Extensions.cpp
index 3d350c98892b..06c8a21b019b 100644
--- a/libs/hwui/Extensions.cpp
+++ b/libs/hwui/Extensions.cpp
@@ -18,23 +18,14 @@
#include "Debug.h"
#include "Properties.h"
+#include "utils/StringUtils.h"
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
#include <GLES2/gl2ext.h>
#include <utils/Log.h>
namespace android {
-
-using namespace uirenderer;
-ANDROID_SINGLETON_STATIC_INSTANCE(Extensions);
-
namespace uirenderer {
-///////////////////////////////////////////////////////////////////////////////
-// Defines
-///////////////////////////////////////////////////////////////////////////////
-
// Debug
#if DEBUG_EXTENSIONS
#define EXT_LOGD(...) ALOGD(__VA_ARGS__)
@@ -42,20 +33,16 @@ namespace uirenderer {
#define EXT_LOGD(...)
#endif
-///////////////////////////////////////////////////////////////////////////////
-// Constructors
-///////////////////////////////////////////////////////////////////////////////
Extensions::Extensions() {
- // Query GL extensions
- findExtensions((const char*) glGetString(GL_EXTENSIONS), mGlExtensionList);
- mHasNPot = hasGlExtension("GL_OES_texture_npot");
- mHasFramebufferFetch = hasGlExtension("GL_NV_shader_framebuffer_fetch");
- mHasDiscardFramebuffer = hasGlExtension("GL_EXT_discard_framebuffer");
- mHasDebugMarker = hasGlExtension("GL_EXT_debug_marker");
- mHas1BitStencil = hasGlExtension("GL_OES_stencil1");
- mHas4BitStencil = hasGlExtension("GL_OES_stencil4");
- mHasUnpackSubImage = hasGlExtension("GL_EXT_unpack_subimage");
+ StringCollection extensions((const char*) glGetString(GL_EXTENSIONS));
+ mHasNPot = extensions.has("GL_OES_texture_npot");
+ mHasFramebufferFetch = extensions.has("GL_NV_shader_framebuffer_fetch");
+ mHasDiscardFramebuffer = extensions.has("GL_EXT_discard_framebuffer");
+ mHasDebugMarker = extensions.has("GL_EXT_debug_marker");
+ mHas1BitStencil = extensions.has("GL_OES_stencil1");
+ mHas4BitStencil = extensions.has("GL_OES_stencil4");
+ mHasUnpackSubImage = extensions.has("GL_EXT_unpack_subimage");
const char* version = (const char*) glGetString(GL_VERSION);
@@ -78,40 +65,5 @@ Extensions::Extensions() {
}
}
-///////////////////////////////////////////////////////////////////////////////
-// Methods
-///////////////////////////////////////////////////////////////////////////////
-
-bool Extensions::hasGlExtension(const char* extension) const {
- const String8 s(extension);
- return mGlExtensionList.indexOf(s) >= 0;
-}
-
-bool Extensions::hasEglExtension(const char* extension) const {
- const String8 s(extension);
- return mEglExtensionList.indexOf(s) >= 0;
-}
-
-void Extensions::findExtensions(const char* extensions, SortedVector<String8>& list) const {
- const char* current = extensions;
- const char* head = current;
- EXT_LOGD("Available extensions:");
- do {
- head = strchr(current, ' ');
- String8 s(current, head ? head - current : strlen(current));
- if (s.length()) {
- list.add(s);
- EXT_LOGD(" %s", s.string());
- }
- current = head + 1;
- } while (head);
-}
-
-void Extensions::dump() const {
- ALOGD("%s", (const char*) glGetString(GL_VERSION));
- ALOGD("Supported GL extensions:\n%s", (const char*) glGetString(GL_EXTENSIONS));
- ALOGD("Supported EGL extensions:\n%s", eglQueryString(eglGetCurrentDisplay(), EGL_EXTENSIONS));
-}
-
}; // namespace uirenderer
}; // namespace android
diff --git a/libs/hwui/Extensions.h b/libs/hwui/Extensions.h
index 636b631532bf..0a30d162f2e8 100644
--- a/libs/hwui/Extensions.h
+++ b/libs/hwui/Extensions.h
@@ -50,17 +50,7 @@ public:
inline int getMajorGlVersion() const { return mVersionMajor; }
inline int getMinorGlVersion() const { return mVersionMinor; }
- bool hasGlExtension(const char* extension) const;
- bool hasEglExtension(const char* extension) const;
-
- void dump() const;
-
private:
- void findExtensions(const char* extensions, SortedVector<String8>& list) const;
-
- SortedVector<String8> mGlExtensionList;
- SortedVector<String8> mEglExtensionList;
-
bool mHasNPot;
bool mHasFramebufferFetch;
bool mHasDiscardFramebuffer;
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 75c3ead68f7b..4b9d4f90675c 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -75,8 +75,8 @@ void TextDrawFunctor::draw(CacheTexture& texture, bool linearFiltering) {
static bool sLogFontRendererCreate = true;
-FontRenderer::FontRenderer()
- : mGammaTable(nullptr)
+FontRenderer::FontRenderer(const uint8_t* gammaTable)
+ : mGammaTable(gammaTable)
, mCurrentFont(nullptr)
, mActiveFonts(LruCache<Font::FontDescription, Font*>::kUnlimitedCapacity)
, mCurrentCacheTexture(nullptr)
@@ -92,27 +92,15 @@ FontRenderer::FontRenderer()
INIT_LOGD("Creating FontRenderer");
}
- mSmallCacheWidth = DEFAULT_TEXT_SMALL_CACHE_WIDTH;
- mSmallCacheHeight = DEFAULT_TEXT_SMALL_CACHE_HEIGHT;
- mLargeCacheWidth = DEFAULT_TEXT_LARGE_CACHE_WIDTH;
- mLargeCacheHeight = DEFAULT_TEXT_LARGE_CACHE_HEIGHT;
+ mSmallCacheWidth = property_get_int32(PROPERTY_TEXT_SMALL_CACHE_WIDTH,
+ DEFAULT_TEXT_SMALL_CACHE_WIDTH);
+ mSmallCacheHeight = property_get_int32(PROPERTY_TEXT_SMALL_CACHE_HEIGHT,
+ DEFAULT_TEXT_SMALL_CACHE_HEIGHT);
- char property[PROPERTY_VALUE_MAX];
- if (property_get(PROPERTY_TEXT_SMALL_CACHE_WIDTH, property, nullptr) > 0) {
- mSmallCacheWidth = atoi(property);
- }
-
- if (property_get(PROPERTY_TEXT_SMALL_CACHE_HEIGHT, property, nullptr) > 0) {
- mSmallCacheHeight = atoi(property);
- }
-
- if (property_get(PROPERTY_TEXT_LARGE_CACHE_WIDTH, property, nullptr) > 0) {
- mLargeCacheWidth = atoi(property);
- }
-
- if (property_get(PROPERTY_TEXT_LARGE_CACHE_HEIGHT, property, nullptr) > 0) {
- mLargeCacheHeight = atoi(property);
- }
+ mLargeCacheWidth = property_get_int32(PROPERTY_TEXT_LARGE_CACHE_WIDTH,
+ DEFAULT_TEXT_LARGE_CACHE_WIDTH);
+ mLargeCacheHeight = property_get_int32(PROPERTY_TEXT_LARGE_CACHE_HEIGHT,
+ DEFAULT_TEXT_LARGE_CACHE_HEIGHT);
uint32_t maxTextureSize = (uint32_t) Caches::getInstance().maxTextureSize;
diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h
index 2954975b1413..936c838bd6e4 100644
--- a/libs/hwui/FontRenderer.h
+++ b/libs/hwui/FontRenderer.h
@@ -72,16 +72,12 @@ public:
class FontRenderer {
public:
- FontRenderer();
+ FontRenderer(const uint8_t* gammaTable);
~FontRenderer();
void flushLargeCaches(std::vector<CacheTexture*>& cacheTextures);
void flushLargeCaches();
- void setGammaTable(const uint8_t* gammaTable) {
- mGammaTable = gammaTable;
- }
-
void setFont(const SkPaint* paint, const SkMatrix& matrix);
void precache(const SkPaint* paint, const char* text, int numGlyphs, const SkMatrix& matrix);
diff --git a/libs/hwui/GammaFontRenderer.cpp b/libs/hwui/GammaFontRenderer.cpp
index 0bcd83a1a050..96cac86386b5 100644
--- a/libs/hwui/GammaFontRenderer.cpp
+++ b/libs/hwui/GammaFontRenderer.cpp
@@ -21,231 +21,22 @@
namespace android {
namespace uirenderer {
-///////////////////////////////////////////////////////////////////////////////
-// Utils
-///////////////////////////////////////////////////////////////////////////////
-
-static int luminance(const SkPaint* paint) {
- uint32_t c = paint->getColor();
- const int r = (c >> 16) & 0xFF;
- const int g = (c >> 8) & 0xFF;
- const int b = (c ) & 0xFF;
- return (r * 2 + g * 5 + b) >> 3;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Base class GammaFontRenderer
-///////////////////////////////////////////////////////////////////////////////
-
-GammaFontRenderer* GammaFontRenderer::createRenderer() {
- // Choose the best renderer
- char property[PROPERTY_VALUE_MAX];
- if (property_get(PROPERTY_TEXT_GAMMA_METHOD, property, DEFAULT_TEXT_GAMMA_METHOD) > 0) {
- if (!strcasecmp(property, "lookup")) {
- return new LookupGammaFontRenderer();
- } else if (!strcasecmp(property, "shader")) {
- return new ShaderGammaFontRenderer(false);
- } else if (!strcasecmp(property, "shader3")) {
- return new ShaderGammaFontRenderer(true);
- }
- }
-
- return new Lookup3GammaFontRenderer();
-}
-
GammaFontRenderer::GammaFontRenderer() {
- // Get the renderer properties
- char property[PROPERTY_VALUE_MAX];
-
- // Get the gamma
- mGamma = DEFAULT_TEXT_GAMMA;
- if (property_get(PROPERTY_TEXT_GAMMA, property, nullptr) > 0) {
- INIT_LOGD(" Setting text gamma to %s", property);
- mGamma = atof(property);
- } else {
- INIT_LOGD(" Using default text gamma of %.2f", DEFAULT_TEXT_GAMMA);
- }
-
- // Get the black gamma threshold
- mBlackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD;
- if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, nullptr) > 0) {
- INIT_LOGD(" Setting text black gamma threshold to %s", property);
- mBlackThreshold = atoi(property);
- } else {
- INIT_LOGD(" Using default text black gamma threshold of %d",
- DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD);
- }
-
- // Get the white gamma threshold
- mWhiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD;
- if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, nullptr) > 0) {
- INIT_LOGD(" Setting text white gamma threshold to %s", property);
- mWhiteThreshold = atoi(property);
- } else {
- INIT_LOGD(" Using default white black gamma threshold of %d",
- DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD);
- }
-}
-
-GammaFontRenderer::~GammaFontRenderer() {
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Shader-based renderer
-///////////////////////////////////////////////////////////////////////////////
-
-ShaderGammaFontRenderer::ShaderGammaFontRenderer(bool multiGamma)
- : GammaFontRenderer() {
- INIT_LOGD("Creating shader gamma font renderer");
- mRenderer = nullptr;
- mMultiGamma = multiGamma;
-}
-
-void ShaderGammaFontRenderer::describe(ProgramDescription& description,
- const SkPaint* paint) const {
- if (paint->getShader() == nullptr) {
- if (mMultiGamma) {
- const int l = luminance(paint);
-
- if (l <= mBlackThreshold) {
- description.hasGammaCorrection = true;
- description.gamma = mGamma;
- } else if (l >= mWhiteThreshold) {
- description.hasGammaCorrection = true;
- description.gamma = 1.0f / mGamma;
- }
- } else {
- description.hasGammaCorrection = true;
- description.gamma = 1.0f / mGamma;
- }
- }
-}
-
-void ShaderGammaFontRenderer::setupProgram(ProgramDescription& description,
- Program& program) const {
- if (description.hasGammaCorrection) {
- glUniform1f(program.getUniform("gamma"), description.gamma);
- }
-}
-
-void ShaderGammaFontRenderer::endPrecaching() {
- if (mRenderer) {
- mRenderer->endPrecaching();
- }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Lookup-based renderer
-///////////////////////////////////////////////////////////////////////////////
-
-LookupGammaFontRenderer::LookupGammaFontRenderer()
- : GammaFontRenderer() {
INIT_LOGD("Creating lookup gamma font renderer");
// Compute the gamma tables
- const float gamma = 1.0f / mGamma;
+ const float gamma = 1.0f / Properties::textGamma;
for (uint32_t i = 0; i <= 255; i++) {
mGammaTable[i] = uint8_t((float)::floor(pow(i / 255.0f, gamma) * 255.0f + 0.5f));
}
-
- mRenderer = nullptr;
}
-void LookupGammaFontRenderer::endPrecaching() {
+void GammaFontRenderer::endPrecaching() {
if (mRenderer) {
mRenderer->endPrecaching();
}
}
-///////////////////////////////////////////////////////////////////////////////
-// Lookup-based renderer, using 3 different correction tables
-///////////////////////////////////////////////////////////////////////////////
-
-Lookup3GammaFontRenderer::Lookup3GammaFontRenderer()
- : GammaFontRenderer() {
- INIT_LOGD("Creating lookup3 gamma font renderer");
-
- // Compute the gamma tables
- const float blackGamma = mGamma;
- const float whiteGamma = 1.0f / mGamma;
-
- for (uint32_t i = 0; i <= 255; i++) {
- const float v = i / 255.0f;
- const float black = pow(v, blackGamma);
- const float white = pow(v, whiteGamma);
-
- mGammaTable[i] = i;
- mGammaTable[256 + i] = uint8_t((float)::floor(black * 255.0f + 0.5f));
- mGammaTable[512 + i] = uint8_t((float)::floor(white * 255.0f + 0.5f));
- }
-
- memset(mRenderers, 0, sizeof(FontRenderer*) * kGammaCount);
- memset(mRenderersUsageCount, 0, sizeof(uint32_t) * kGammaCount);
-}
-
-void Lookup3GammaFontRenderer::endPrecaching() {
- for (int i = 0; i < kGammaCount; i++) {
- if (mRenderers[i]) {
- mRenderers[i]->endPrecaching();
- }
- }
-}
-
-void Lookup3GammaFontRenderer::clear() {
- for (int i = 0; i < kGammaCount; i++) {
- mRenderers[i].release();
- }
-}
-
-void Lookup3GammaFontRenderer::flush() {
- int count = 0;
- int min = -1;
- uint32_t minCount = UINT_MAX;
-
- for (int i = 0; i < kGammaCount; i++) {
- if (mRenderers[i]) {
- count++;
- if (mRenderersUsageCount[i] < minCount) {
- minCount = mRenderersUsageCount[i];
- min = i;
- }
- }
- }
-
- if (count <= 1 || min < 0) return;
-
- mRenderers[min].release();
-
- // Also eliminate the caches for large glyphs, as they consume significant memory
- for (int i = 0; i < kGammaCount; ++i) {
- if (mRenderers[i]) {
- mRenderers[i]->flushLargeCaches();
- }
- }
-}
-
-FontRenderer* Lookup3GammaFontRenderer::getRenderer(Gamma gamma) {
- if (!mRenderers[gamma]) {
- mRenderers[gamma].reset(new FontRenderer());
- mRenderers[gamma]->setGammaTable(&mGammaTable[gamma * 256]);
- }
- mRenderersUsageCount[gamma]++;
- return mRenderers[gamma].get();
-}
-
-FontRenderer& Lookup3GammaFontRenderer::getFontRenderer(const SkPaint* paint) {
- if (paint->getShader() == nullptr) {
- const int l = luminance(paint);
-
- if (l <= mBlackThreshold) {
- return *getRenderer(kGammaBlack);
- } else if (l >= mWhiteThreshold) {
- return *getRenderer(kGammaWhite);
- }
- }
- return *getRenderer(kGammaDefault);
-}
-
}; // namespace uirenderer
}; // namespace android
diff --git a/libs/hwui/GammaFontRenderer.h b/libs/hwui/GammaFontRenderer.h
index ca55bf1e74e0..146d385e1173 100644
--- a/libs/hwui/GammaFontRenderer.h
+++ b/libs/hwui/GammaFontRenderer.h
@@ -17,183 +17,44 @@
#ifndef ANDROID_HWUI_GAMMA_FONT_RENDERER_H
#define ANDROID_HWUI_GAMMA_FONT_RENDERER_H
-#include <SkPaint.h>
-
#include "FontRenderer.h"
#include "Program.h"
+#include <SkPaint.h>
+
namespace android {
namespace uirenderer {
class GammaFontRenderer {
public:
- virtual ~GammaFontRenderer();
-
- virtual void clear() = 0;
- virtual void flush() = 0;
-
- virtual FontRenderer& getFontRenderer(const SkPaint* paint) = 0;
-
- virtual uint32_t getFontRendererCount() const = 0;
- virtual uint32_t getFontRendererSize(uint32_t fontRenderer, GLenum format) const = 0;
-
- virtual void describe(ProgramDescription& description, const SkPaint* paint) const = 0;
- virtual void setupProgram(ProgramDescription& description, Program& program) const = 0;
-
- virtual void endPrecaching() = 0;
-
- static GammaFontRenderer* createRenderer();
-
-protected:
GammaFontRenderer();
- int mBlackThreshold;
- int mWhiteThreshold;
-
- float mGamma;
-};
-
-class ShaderGammaFontRenderer: public GammaFontRenderer {
-public:
- ~ShaderGammaFontRenderer() {
- delete mRenderer;
- }
-
- void clear() override {
- delete mRenderer;
- mRenderer = nullptr;
- }
-
- void flush() override {
- if (mRenderer) {
- mRenderer->flushLargeCaches();
- }
- }
-
- FontRenderer& getFontRenderer(const SkPaint* paint) override {
- if (!mRenderer) {
- mRenderer = new FontRenderer;
- }
- return *mRenderer;
- }
-
- uint32_t getFontRendererCount() const override {
- return 1;
- }
-
- uint32_t getFontRendererSize(uint32_t fontRenderer, GLenum format) const override {
- return mRenderer ? mRenderer->getCacheSize(format) : 0;
- }
-
- void describe(ProgramDescription& description, const SkPaint* paint) const override;
- void setupProgram(ProgramDescription& description, Program& program) const override;
-
- void endPrecaching() override;
-
-private:
- ShaderGammaFontRenderer(bool multiGamma);
-
- FontRenderer* mRenderer;
- bool mMultiGamma;
-
- friend class GammaFontRenderer;
-};
-
-class LookupGammaFontRenderer: public GammaFontRenderer {
-public:
- ~LookupGammaFontRenderer() {
- delete mRenderer;
- }
-
- void clear() override {
- delete mRenderer;
- mRenderer = nullptr;
+ void clear() {
+ mRenderer.release();
}
- void flush() override {
+ void flush() {
if (mRenderer) {
mRenderer->flushLargeCaches();
}
}
- FontRenderer& getFontRenderer(const SkPaint* paint) override {
+ FontRenderer& getFontRenderer() {
if (!mRenderer) {
- mRenderer = new FontRenderer;
- mRenderer->setGammaTable(&mGammaTable[0]);
+ mRenderer.reset(new FontRenderer(&mGammaTable[0]));
}
return *mRenderer;
}
- uint32_t getFontRendererCount() const override {
- return 1;
- }
-
- uint32_t getFontRendererSize(uint32_t fontRenderer, GLenum format) const override {
+ uint32_t getFontRendererSize(GLenum format) const {
return mRenderer ? mRenderer->getCacheSize(format) : 0;
}
- void describe(ProgramDescription& description, const SkPaint* paint) const override {
- }
-
- void setupProgram(ProgramDescription& description, Program& program) const override {
- }
-
- void endPrecaching() override;
+ void endPrecaching();
private:
- LookupGammaFontRenderer();
-
- FontRenderer* mRenderer;
+ std::unique_ptr<FontRenderer> mRenderer;
uint8_t mGammaTable[256];
-
- friend class GammaFontRenderer;
-};
-
-class Lookup3GammaFontRenderer: public GammaFontRenderer {
-public:
- void clear() override;
- void flush() override;
-
- FontRenderer& getFontRenderer(const SkPaint* paint) override;
-
- uint32_t getFontRendererCount() const override {
- return kGammaCount;
- }
-
- uint32_t getFontRendererSize(uint32_t fontRenderer, GLenum format) const override {
- if (fontRenderer >= kGammaCount) return 0;
-
- if (!mRenderers[fontRenderer]) return 0;
-
- return mRenderers[fontRenderer]->getCacheSize(format);
- }
-
- void describe(ProgramDescription& description, const SkPaint* paint) const override {
- }
-
- void setupProgram(ProgramDescription& description, Program& program) const override {
- }
-
- void endPrecaching() override;
-
-private:
- Lookup3GammaFontRenderer();
-
- enum Gamma {
- kGammaDefault = 0,
- kGammaBlack = 1,
- kGammaWhite = 2,
- kGammaCount = 3
- };
-
- FontRenderer* getRenderer(Gamma gamma);
-
- uint32_t mRenderersUsageCount[kGammaCount];
- std::unique_ptr<FontRenderer> mRenderers[kGammaCount];
-
- uint8_t mGammaTable[256 * kGammaCount];
-
- friend class GammaFontRenderer;
};
}; // namespace uirenderer
diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp
index e27b26b1d091..69559a77c3a0 100644
--- a/libs/hwui/GlopBuilder.cpp
+++ b/libs/hwui/GlopBuilder.cpp
@@ -435,7 +435,6 @@ GlopBuilder& GlopBuilder::setFillLayer(Texture& texture, const SkColorFilter* co
mOutGlop->fill.texture = { &texture,
GL_TEXTURE_2D, GL_LINEAR, GL_CLAMP_TO_EDGE, nullptr };
- mOutGlop->fill.color = { alpha, alpha, alpha, alpha };
setFill(SK_ColorWHITE, alpha, mode, modeUsage, nullptr, colorFilter);
@@ -449,7 +448,6 @@ GlopBuilder& GlopBuilder::setFillTextureLayer(Layer& layer, float alpha) {
mOutGlop->fill.texture = { &(layer.getTexture()),
layer.getRenderTarget(), GL_LINEAR, GL_CLAMP_TO_EDGE, &layer.getTexTransform() };
- mOutGlop->fill.color = { alpha, alpha, alpha, alpha };
setFill(SK_ColorWHITE, alpha, layer.getMode(), Blend::ModeOrderSwap::NoSwap,
nullptr, layer.getColorFilter());
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index e06e34849a91..a401ce119021 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -2014,7 +2014,7 @@ void OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count,
y = floorf(y + currentTransform()->getTranslateY() + 0.5f);
}
- FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
+ FontRenderer& fontRenderer = mCaches.fontRenderer.getFontRenderer();
fontRenderer.setFont(paint, SkMatrix::I());
int alpha;
@@ -2166,7 +2166,7 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, float
SkXfermode::Mode mode;
getAlphaAndMode(paint, &alpha, &mode);
- FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
+ FontRenderer& fontRenderer = mCaches.fontRenderer.getFontRenderer();
if (CC_UNLIKELY(hasTextShadow(paint))) {
fontRenderer.setFont(paint, SkMatrix::I());
@@ -2234,7 +2234,7 @@ void OpenGLRenderer::drawTextOnPath(const char* text, int bytesCount, int count,
// TODO: avoid scissor by calculating maximum bounds using path bounds + font metrics
mRenderState.scissor().setEnabled(true);
- FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
+ FontRenderer& fontRenderer = mCaches.fontRenderer.getFontRenderer();
fontRenderer.setFont(paint, SkMatrix::I());
fontRenderer.setTextureFiltering(true);
diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp
index f503e5d6e8ba..4031f2e13f39 100644
--- a/libs/hwui/PathCache.cpp
+++ b/libs/hwui/PathCache.cpp
@@ -138,10 +138,10 @@ PathCache::PathCache():
mSize(0), mMaxSize(MB(DEFAULT_PATH_CACHE_SIZE)) {
char property[PROPERTY_VALUE_MAX];
if (property_get(PROPERTY_PATH_CACHE_SIZE, property, nullptr) > 0) {
- INIT_LOGD(" Setting %s cache size to %sMB", name, property);
+ INIT_LOGD(" Setting path cache size to %sMB", property);
mMaxSize = MB(atof(property));
} else {
- INIT_LOGD(" Using default %s cache size of %.2fMB", name, DEFAULT_PATH_CACHE_SIZE);
+ INIT_LOGD(" Using default path cache size of %.2fMB", DEFAULT_PATH_CACHE_SIZE);
}
mCache.setOnEntryRemovedListener(this);
diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h
index b09c207f6e45..e5200a516777 100644
--- a/libs/hwui/Program.h
+++ b/libs/hwui/Program.h
@@ -78,14 +78,12 @@ namespace uirenderer {
#define PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT 38
#define PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT 39
-#define PROGRAM_HAS_GAMMA_CORRECTION 40
+#define PROGRAM_IS_SIMPLE_GRADIENT 40
-#define PROGRAM_IS_SIMPLE_GRADIENT 41
+#define PROGRAM_HAS_COLORS 41
-#define PROGRAM_HAS_COLORS 42
-
-#define PROGRAM_HAS_DEBUG_HIGHLIGHT 43
-#define PROGRAM_HAS_ROUND_RECT_CLIP 44
+#define PROGRAM_HAS_DEBUG_HIGHLIGHT 42
+#define PROGRAM_HAS_ROUND_RECT_CLIP 43
///////////////////////////////////////////////////////////////////////////////
// Types
@@ -157,9 +155,6 @@ struct ProgramDescription {
SkXfermode::Mode framebufferMode;
bool swapSrcDst;
- bool hasGammaCorrection;
- float gamma;
-
bool hasDebugHighlight;
bool hasRoundRectClip;
@@ -199,9 +194,6 @@ struct ProgramDescription {
framebufferMode = SkXfermode::kClear_Mode;
swapSrcDst = false;
- hasGammaCorrection = false;
- gamma = 2.2f;
-
hasDebugHighlight = false;
hasRoundRectClip = false;
}
@@ -266,7 +258,6 @@ struct ProgramDescription {
if (useShadowAlphaInterp) key |= programid(0x1) << PROGRAM_USE_SHADOW_ALPHA_INTERP_SHIFT;
if (hasExternalTexture) key |= programid(0x1) << PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT;
if (hasTextureTransform) key |= programid(0x1) << PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT;
- if (hasGammaCorrection) key |= programid(0x1) << PROGRAM_HAS_GAMMA_CORRECTION;
if (isSimpleGradient) key |= programid(0x1) << PROGRAM_IS_SIMPLE_GRADIENT;
if (hasColors) key |= programid(0x1) << PROGRAM_HAS_COLORS;
if (hasDebugHighlight) key |= programid(0x1) << PROGRAM_HAS_DEBUG_HIGHLIGHT;
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index b25a4ac9558d..05be48822fb2 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -167,8 +167,6 @@ const char* gFS_Uniforms_ColorOp[3] = {
// PorterDuff
"uniform vec4 colorBlend;\n"
};
-const char* gFS_Uniforms_Gamma =
- "uniform float gamma;\n";
const char* gFS_Uniforms_HasRoundRectClip =
"uniform vec4 roundRectInnerRectLTRB;\n"
@@ -204,18 +202,10 @@ const char* gFS_Fast_SingleA8Texture =
"\nvoid main(void) {\n"
" gl_FragColor = texture2D(baseSampler, outTexCoords);\n"
"}\n\n";
-const char* gFS_Fast_SingleA8Texture_ApplyGamma =
- "\nvoid main(void) {\n"
- " gl_FragColor = vec4(0.0, 0.0, 0.0, pow(texture2D(baseSampler, outTexCoords).a, gamma));\n"
- "}\n\n";
const char* gFS_Fast_SingleModulateA8Texture =
"\nvoid main(void) {\n"
" gl_FragColor = color * texture2D(baseSampler, outTexCoords).a;\n"
"}\n\n";
-const char* gFS_Fast_SingleModulateA8Texture_ApplyGamma =
- "\nvoid main(void) {\n"
- " gl_FragColor = color * pow(texture2D(baseSampler, outTexCoords).a, gamma);\n"
- "}\n\n";
const char* gFS_Fast_SingleGradient[2] = {
"\nvoid main(void) {\n"
" gl_FragColor = %s + texture2D(gradientSampler, linear);\n"
@@ -250,13 +240,11 @@ const char* gFS_Main_FetchTexture[2] = {
// Modulate
" fragColor = color * texture2D(baseSampler, outTexCoords);\n"
};
-const char* gFS_Main_FetchA8Texture[4] = {
+const char* gFS_Main_FetchA8Texture[2] = {
// Don't modulate
" fragColor = texture2D(baseSampler, outTexCoords);\n",
- " fragColor = texture2D(baseSampler, outTexCoords);\n",
// Modulate
" fragColor = color * texture2D(baseSampler, outTexCoords).a;\n",
- " fragColor = color * pow(texture2D(baseSampler, outTexCoords).a, gamma);\n"
};
const char* gFS_Main_FetchGradient[6] = {
// Linear
@@ -284,38 +272,29 @@ const char* gFS_Main_BlendShadersBG =
" fragColor = blendShaders(gradientColor, bitmapColor)";
const char* gFS_Main_BlendShadersGB =
" fragColor = blendShaders(bitmapColor, gradientColor)";
-const char* gFS_Main_BlendShaders_Modulate[6] = {
+const char* gFS_Main_BlendShaders_Modulate[3] = {
// Don't modulate
";\n",
- ";\n",
// Modulate
" * color.a;\n",
- " * color.a;\n",
// Modulate with alpha 8 texture
" * texture2D(baseSampler, outTexCoords).a;\n",
- " * pow(texture2D(baseSampler, outTexCoords).a, gamma);\n"
};
-const char* gFS_Main_GradientShader_Modulate[6] = {
+const char* gFS_Main_GradientShader_Modulate[3] = {
// Don't modulate
" fragColor = gradientColor;\n",
- " fragColor = gradientColor;\n",
// Modulate
" fragColor = gradientColor * color.a;\n",
- " fragColor = gradientColor * color.a;\n",
// Modulate with alpha 8 texture
" fragColor = gradientColor * texture2D(baseSampler, outTexCoords).a;\n",
- " fragColor = gradientColor * pow(texture2D(baseSampler, outTexCoords).a, gamma);\n"
};
-const char* gFS_Main_BitmapShader_Modulate[6] = {
+const char* gFS_Main_BitmapShader_Modulate[3] = {
// Don't modulate
" fragColor = bitmapColor;\n",
- " fragColor = bitmapColor;\n",
// Modulate
" fragColor = bitmapColor * color.a;\n",
- " fragColor = bitmapColor * color.a;\n",
// Modulate with alpha 8 texture
" fragColor = bitmapColor * texture2D(baseSampler, outTexCoords).a;\n",
- " fragColor = bitmapColor * pow(texture2D(baseSampler, outTexCoords).a, gamma);\n"
};
const char* gFS_Main_FragColor =
" gl_FragColor = fragColor;\n";
@@ -540,7 +519,6 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description
static bool shaderOp(const ProgramDescription& description, String8& shader,
const int modulateOp, const char** snippets) {
int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp;
- op = op * 2 + description.hasGammaCorrection;
shader.append(snippets[op]);
return description.hasAlpha8Texture;
}
@@ -596,9 +574,6 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
shader.appendFormat(gFS_Uniforms_GradientSampler[description.isSimpleGradient],
gFS_Uniforms_Dither);
}
- if (description.hasGammaCorrection) {
- shader.append(gFS_Uniforms_Gamma);
- }
if (description.hasRoundRectClip) {
shader.append(gFS_Uniforms_HasRoundRectClip);
}
@@ -633,17 +608,9 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
fast = true;
} else if (singleA8Texture) {
if (!description.modulate) {
- if (description.hasGammaCorrection) {
- shader.append(gFS_Fast_SingleA8Texture_ApplyGamma);
- } else {
- shader.append(gFS_Fast_SingleA8Texture);
- }
+ shader.append(gFS_Fast_SingleA8Texture);
} else {
- if (description.hasGammaCorrection) {
- shader.append(gFS_Fast_SingleModulateA8Texture_ApplyGamma);
- } else {
- shader.append(gFS_Fast_SingleModulateA8Texture);
- }
+ shader.append(gFS_Fast_SingleModulateA8Texture);
}
fast = true;
} else if (singleGradient) {
@@ -693,8 +660,7 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
if (description.hasTexture || description.hasExternalTexture) {
if (description.hasAlpha8Texture) {
if (!description.hasGradient && !description.hasBitmap) {
- shader.append(gFS_Main_FetchA8Texture[modulateOp * 2 +
- description.hasGammaCorrection]);
+ shader.append(gFS_Main_FetchA8Texture[modulateOp]);
}
} else {
shader.append(gFS_Main_FetchTexture[modulateOp]);
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index b8f8585e5af6..36a8dac9d0c1 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -33,6 +33,8 @@ bool Properties::swapBuffersWithDamage = true;
bool Properties::useBufferAge = true;
bool Properties::enablePartialUpdates = true;
+float Properties::textGamma = DEFAULT_TEXT_GAMMA;
+
DebugLevel Properties::debugLevel = kDebugDisabled;
OverdrawColorSet Properties::overdrawColorSet = OverdrawColorSet::Default;
StencilClipDebug Properties::debugStencilClip = StencilClipDebug::Hide;
@@ -47,6 +49,15 @@ int Properties::overrideSpotShadowStrength = -1;
ProfileType Properties::sProfileType = ProfileType::None;
bool Properties::sDisableProfileBars = false;
+static float property_get_float(const char* key, float defaultValue) {
+ char buf[PROPERTY_VALUE_MAX] = {'\0',};
+
+ if (property_get(PROPERTY_PROFILE, buf, "") > 0) {
+ return atof(buf);
+ }
+ return defaultValue;
+}
+
bool Properties::load() {
char property[PROPERTY_VALUE_MAX];
bool prevDebugLayersUpdates = debugLayersUpdates;
@@ -110,6 +121,8 @@ bool Properties::load() {
useBufferAge = property_get_bool(PROPERTY_USE_BUFFER_AGE, true);
enablePartialUpdates = property_get_bool(PROPERTY_ENABLE_PARTIAL_UPDATES, true);
+ textGamma = property_get_float(PROPERTY_TEXT_GAMMA, DEFAULT_TEXT_GAMMA);
+
return (prevDebugLayersUpdates != debugLayersUpdates)
|| (prevDebugOverdraw != debugOverdraw)
|| (prevDebugStencilClip != debugStencilClip);
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 76028482ba86..3512c36417e1 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -208,30 +208,8 @@ enum DebugLevel {
#define PROPERTY_TEXT_LARGE_CACHE_WIDTH "ro.hwui.text_large_cache_width"
#define PROPERTY_TEXT_LARGE_CACHE_HEIGHT "ro.hwui.text_large_cache_height"
-// Indicates whether gamma correction should be applied in the shaders
-// or in lookup tables. Accepted values:
-//
-// - "lookup3", correction based on lookup tables. Gamma correction
-// is different for black and white text (see thresholds below)
-//
-// - "lookup", correction based on a single lookup table
-//
-// - "shader3", correction applied by a GLSL shader. Gamma correction
-// is different for black and white text (see thresholds below)
-//
-// - "shader", correction applied by a GLSL shader
-//
-// See PROPERTY_TEXT_GAMMA, PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD and
-// PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD for more control.
-#define PROPERTY_TEXT_GAMMA_METHOD "hwui.text_gamma_correction"
-#define DEFAULT_TEXT_GAMMA_METHOD "lookup"
-
// Gamma (>= 1.0, <= 10.0)
#define PROPERTY_TEXT_GAMMA "hwui.text_gamma"
-// Luminance threshold below which black gamma correction is applied. Range: [0..255]
-#define PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD "hwui.text_gamma.black_threshold"
-// Lumincance threshold above which white gamma correction is applied. Range: [0..255]
-#define PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD "hwui.text_gamma.white_threshold"
///////////////////////////////////////////////////////////////////////////////
// Default property values
@@ -242,7 +220,7 @@ enum DebugLevel {
#define DEFAULT_RENDER_BUFFER_CACHE_SIZE 2.0f
#define DEFAULT_PATH_CACHE_SIZE 4.0f
#define DEFAULT_VERTEX_CACHE_SIZE 1.0f
-#define DEFAULT_PATCH_CACHE_SIZE 128 // in kB
+#define DEFAULT_PATCH_CACHE_SIZE 128.0f // in kB
#define DEFAULT_GRADIENT_CACHE_SIZE 0.5f
#define DEFAULT_DROP_SHADOW_CACHE_SIZE 2.0f
#define DEFAULT_FBO_CACHE_SIZE 0
@@ -250,8 +228,6 @@ enum DebugLevel {
#define DEFAULT_TEXTURE_CACHE_FLUSH_RATE 0.6f
#define DEFAULT_TEXT_GAMMA 1.4f
-#define DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD 64
-#define DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD 192
///////////////////////////////////////////////////////////////////////////////
// Misc
@@ -300,6 +276,8 @@ public:
static bool useBufferAge;
static bool enablePartialUpdates;
+ static float textGamma;
+
static DebugLevel debugLevel;
static OverdrawColorSet overdrawColorSet;
static StencilClipDebug debugStencilClip;
diff --git a/libs/hwui/TessellationCache.cpp b/libs/hwui/TessellationCache.cpp
index 01f5e2dba214..12a3e76c9387 100644
--- a/libs/hwui/TessellationCache.cpp
+++ b/libs/hwui/TessellationCache.cpp
@@ -312,10 +312,10 @@ TessellationCache::TessellationCache()
, mShadowCache(LruCache<ShadowDescription, Task<vertexBuffer_pair_t*>*>::kUnlimitedCapacity) {
char property[PROPERTY_VALUE_MAX];
if (property_get(PROPERTY_VERTEX_CACHE_SIZE, property, nullptr) > 0) {
- INIT_LOGD(" Setting %s cache size to %sMB", name, property);
+ INIT_LOGD(" Setting tessellation cache size to %sMB", property);
setMaxSize(MB(atof(property)));
} else {
- INIT_LOGD(" Using default %s cache size of %.2fMB", name, DEFAULT_VERTEX_CACHE_SIZE);
+ INIT_LOGD(" Using default tessellation cache size of %.2fMB", DEFAULT_VERTEX_CACHE_SIZE);
}
mCache.setOnEntryRemovedListener(&mBufferRemovedListener);
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index 16f6f4ba4bb6..a6c72a380805 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -16,9 +16,6 @@
#include <GLES2/gl2.h>
-#include <SkCanvas.h>
-#include <SkPixelRef.h>
-
#include <utils/Mutex.h>
#include "AssetAtlas.h"
@@ -169,7 +166,7 @@ Texture* TextureCache::getCachedTexture(const SkBitmap* bitmap, AtlasUsageType a
if (canCache) {
texture = new Texture(Caches::getInstance());
texture->bitmapSize = size;
- generateTexture(bitmap, texture, false);
+ Caches::getInstance().textureState().generateTexture(bitmap, texture, false);
mSize += size;
TEXTURE_LOGD("TextureCache::get: create texture(%p): name, size, mSize = %d, %d, %d",
@@ -182,7 +179,7 @@ Texture* TextureCache::getCachedTexture(const SkBitmap* bitmap, AtlasUsageType a
} else if (!texture->isInUse && bitmap->getGenerationID() != texture->generation) {
// Texture was in the cache but is dirty, re-upload
// TODO: Re-adjust the cache size if the bitmap's dimensions have changed
- generateTexture(bitmap, texture, true);
+ Caches::getInstance().textureState().generateTexture(bitmap, texture, true);
}
return texture;
@@ -207,7 +204,7 @@ Texture* TextureCache::get(const SkBitmap* bitmap, AtlasUsageType atlasUsageType
const uint32_t size = bitmap->rowBytes() * bitmap->height();
texture = new Texture(Caches::getInstance());
texture->bitmapSize = size;
- generateTexture(bitmap, texture, false);
+ Caches::getInstance().textureState().generateTexture(bitmap, texture, false);
texture->cleanup = true;
}
@@ -249,133 +246,5 @@ void TextureCache::flush() {
}
}
-void TextureCache::generateTexture(const SkBitmap* bitmap, Texture* texture, bool regenerate) {
- SkAutoLockPixels alp(*bitmap);
-
- if (!bitmap->readyToDraw()) {
- ALOGE("Cannot generate texture from bitmap");
- return;
- }
-
- ATRACE_FORMAT("Upload %ux%u Texture", bitmap->width(), bitmap->height());
-
- // We could also enable mipmapping if both bitmap dimensions are powers
- // of 2 but we'd have to deal with size changes. Let's keep this simple
- const bool canMipMap = Caches::getInstance().extensions().hasNPot();
-
- // If the texture had mipmap enabled but not anymore,
- // force a glTexImage2D to discard the mipmap levels
- const bool resize = !regenerate || bitmap->width() != int(texture->width) ||
- bitmap->height() != int(texture->height) ||
- (regenerate && canMipMap && texture->mipMap && !bitmap->hasHardwareMipMap());
-
- if (!regenerate) {
- glGenTextures(1, &texture->id);
- }
-
- texture->generation = bitmap->getGenerationID();
- texture->width = bitmap->width();
- texture->height = bitmap->height();
-
- Caches::getInstance().textureState().bindTexture(texture->id);
-
- switch (bitmap->colorType()) {
- case kAlpha_8_SkColorType:
- uploadToTexture(resize, GL_ALPHA, bitmap->rowBytesAsPixels(), bitmap->bytesPerPixel(),
- texture->width, texture->height, GL_UNSIGNED_BYTE, bitmap->getPixels());
- texture->blend = true;
- break;
- case kRGB_565_SkColorType:
- uploadToTexture(resize, GL_RGB, bitmap->rowBytesAsPixels(), bitmap->bytesPerPixel(),
- texture->width, texture->height, GL_UNSIGNED_SHORT_5_6_5, bitmap->getPixels());
- texture->blend = false;
- break;
- case kN32_SkColorType:
- uploadToTexture(resize, GL_RGBA, bitmap->rowBytesAsPixels(), bitmap->bytesPerPixel(),
- texture->width, texture->height, GL_UNSIGNED_BYTE, bitmap->getPixels());
- // Do this after calling getPixels() to make sure Skia's deferred
- // decoding happened
- texture->blend = !bitmap->isOpaque();
- break;
- case kARGB_4444_SkColorType:
- case kIndex_8_SkColorType:
- uploadLoFiTexture(resize, bitmap, texture->width, texture->height);
- texture->blend = !bitmap->isOpaque();
- break;
- default:
- ALOGW("Unsupported bitmap colorType: %d", bitmap->colorType());
- break;
- }
-
- if (canMipMap) {
- texture->mipMap = bitmap->hasHardwareMipMap();
- if (texture->mipMap) {
- glGenerateMipmap(GL_TEXTURE_2D);
- }
- }
-
- if (!regenerate) {
- texture->setFilter(GL_NEAREST);
- texture->setWrap(GL_CLAMP_TO_EDGE);
- }
-}
-
-void TextureCache::uploadLoFiTexture(bool resize, const SkBitmap* bitmap,
- uint32_t width, uint32_t height) {
- SkBitmap rgbaBitmap;
- rgbaBitmap.allocPixels(SkImageInfo::MakeN32(width, height, bitmap->alphaType()));
- rgbaBitmap.eraseColor(0);
-
- SkCanvas canvas(rgbaBitmap);
- canvas.drawBitmap(*bitmap, 0.0f, 0.0f, nullptr);
-
- uploadToTexture(resize, GL_RGBA, rgbaBitmap.rowBytesAsPixels(), rgbaBitmap.bytesPerPixel(),
- width, height, GL_UNSIGNED_BYTE, rgbaBitmap.getPixels());
-}
-
-void TextureCache::uploadToTexture(bool resize, GLenum format, GLsizei stride, GLsizei bpp,
- GLsizei width, GLsizei height, GLenum type, const GLvoid * data) {
- glPixelStorei(GL_UNPACK_ALIGNMENT, bpp);
- const bool useStride = stride != width
- && Caches::getInstance().extensions().hasUnpackRowLength();
- if ((stride == width) || useStride) {
- if (useStride) {
- glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
- }
-
- if (resize) {
- glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, data);
- } else {
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, data);
- }
-
- if (useStride) {
- glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
- }
- } else {
- // With OpenGL ES 2.0 we need to copy the bitmap in a temporary buffer
- // if the stride doesn't match the width
-
- GLvoid * temp = (GLvoid *) malloc(width * height * bpp);
- if (!temp) return;
-
- uint8_t * pDst = (uint8_t *)temp;
- uint8_t * pSrc = (uint8_t *)data;
- for (GLsizei i = 0; i < height; i++) {
- memcpy(pDst, pSrc, width * bpp);
- pDst += width * bpp;
- pSrc += stride * bpp;
- }
-
- if (resize) {
- glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, temp);
- } else {
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, temp);
- }
-
- free(temp);
- }
-}
-
}; // namespace uirenderer
}; // namespace android
diff --git a/libs/hwui/TextureCache.h b/libs/hwui/TextureCache.h
index ebd1885e75e1..191c8a81fec6 100644
--- a/libs/hwui/TextureCache.h
+++ b/libs/hwui/TextureCache.h
@@ -144,18 +144,6 @@ private:
Texture* get(const SkBitmap* bitmap, AtlasUsageType atlasUsageType);
Texture* getCachedTexture(const SkBitmap* bitmap, AtlasUsageType atlasUsageType);
- /**
- * Generates the texture from a bitmap into the specified texture structure.
- *
- * @param regenerate If true, the bitmap data is reuploaded into the texture, but
- * no new texture is generated.
- */
- void generateTexture(const SkBitmap* bitmap, Texture* texture, bool regenerate = false);
-
- void uploadLoFiTexture(bool resize, const SkBitmap* bitmap, uint32_t width, uint32_t height);
- void uploadToTexture(bool resize, GLenum format, GLsizei stride, GLsizei bpp,
- GLsizei width, GLsizei height, GLenum type, const GLvoid * data);
-
LruCache<uint32_t, Texture*> mCache;
uint32_t mSize;
diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h
index ed853f72539d..98e61468ea70 100644
--- a/libs/hwui/TreeInfo.h
+++ b/libs/hwui/TreeInfo.h
@@ -77,7 +77,7 @@ public:
, canvasContext(clone.canvasContext)
{}
- const TraversalMode mode;
+ TraversalMode mode;
// TODO: Remove this? Currently this is used to signal to stop preparing
// textures if we run out of cache space.
bool prepareTextures;
diff --git a/libs/hwui/renderstate/Blend.cpp b/libs/hwui/renderstate/Blend.cpp
index b21e15e8fad9..93f787d31745 100644
--- a/libs/hwui/renderstate/Blend.cpp
+++ b/libs/hwui/renderstate/Blend.cpp
@@ -98,20 +98,6 @@ Blend::Blend()
// gl blending off by default
}
-void Blend::enable(SkXfermode::Mode mode, ModeOrderSwap modeUsage) {
- GLenum srcMode;
- GLenum dstMode;
- getFactors(mode, modeUsage, &srcMode, &dstMode);
- setFactors(srcMode, dstMode);
-}
-
-void Blend::disable() {
- if (mEnabled) {
- glDisable(GL_BLEND);
- mEnabled = false;
- }
-}
-
void Blend::invalidate() {
syncEnabled();
mSrcMode = mDstMode = GL_ZERO;
@@ -132,8 +118,13 @@ void Blend::getFactors(SkXfermode::Mode mode, ModeOrderSwap modeUsage, GLenum* o
void Blend::setFactors(GLenum srcMode, GLenum dstMode) {
if (srcMode == GL_ZERO && dstMode == GL_ZERO) {
- disable();
+ // disable blending
+ if (mEnabled) {
+ glDisable(GL_BLEND);
+ mEnabled = false;
+ }
} else {
+ // enable blending
if (!mEnabled) {
glEnable(GL_BLEND);
mEnabled = true;
diff --git a/libs/hwui/renderstate/Blend.h b/libs/hwui/renderstate/Blend.h
index dcc681d4aa50..df9e5a8af879 100644
--- a/libs/hwui/renderstate/Blend.h
+++ b/libs/hwui/renderstate/Blend.h
@@ -34,9 +34,6 @@ public:
NoSwap,
Swap,
};
-
- void enable(SkXfermode::Mode mode, ModeOrderSwap modeUsage);
- void disable();
void syncEnabled();
static void getFactors(SkXfermode::Mode mode, ModeOrderSwap modeUsage,
diff --git a/libs/hwui/renderstate/TextureState.cpp b/libs/hwui/renderstate/TextureState.cpp
index 987d4cd55a5e..1f50f712c267 100644
--- a/libs/hwui/renderstate/TextureState.cpp
+++ b/libs/hwui/renderstate/TextureState.cpp
@@ -15,6 +15,14 @@
*/
#include "renderstate/TextureState.h"
+#include "Caches.h"
+#include "utils/TraceUtils.h"
+
+#include <GLES3/gl3.h>
+#include <memory>
+#include <SkCanvas.h>
+#include <SkBitmap.h>
+
namespace android {
namespace uirenderer {
@@ -26,6 +34,134 @@ const GLenum kTextureUnits[] = {
GL_TEXTURE3
};
+static void uploadToTexture(bool resize, GLenum format, GLenum type, GLsizei stride, GLsizei bpp,
+ GLsizei width, GLsizei height, const GLvoid * data) {
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, bpp);
+ const bool useStride = stride != width
+ && Caches::getInstance().extensions().hasUnpackRowLength();
+ if ((stride == width) || useStride) {
+ if (useStride) {
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
+ }
+
+ if (resize) {
+ glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, data);
+ } else {
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, data);
+ }
+
+ if (useStride) {
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+ }
+ } else {
+ // With OpenGL ES 2.0 we need to copy the bitmap in a temporary buffer
+ // if the stride doesn't match the width
+
+ GLvoid * temp = (GLvoid *) malloc(width * height * bpp);
+ if (!temp) return;
+
+ uint8_t * pDst = (uint8_t *)temp;
+ uint8_t * pSrc = (uint8_t *)data;
+ for (GLsizei i = 0; i < height; i++) {
+ memcpy(pDst, pSrc, width * bpp);
+ pDst += width * bpp;
+ pSrc += stride * bpp;
+ }
+
+ if (resize) {
+ glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, temp);
+ } else {
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, temp);
+ }
+
+ free(temp);
+ }
+}
+
+static void uploadSkBitmapToTexture(const SkBitmap& bitmap,
+ bool resize, GLenum format, GLenum type) {
+ uploadToTexture(resize, format, type, bitmap.rowBytesAsPixels(), bitmap.bytesPerPixel(),
+ bitmap.width(), bitmap.height(), bitmap.getPixels());
+}
+
+void TextureState::generateTexture(const SkBitmap* bitmap, Texture* texture, bool regenerate) {
+ SkAutoLockPixels alp(*bitmap);
+
+ if (!bitmap->readyToDraw()) {
+ ALOGE("Cannot generate texture from bitmap");
+ return;
+ }
+
+ ATRACE_FORMAT("Upload %ux%u Texture", bitmap->width(), bitmap->height());
+
+ // We could also enable mipmapping if both bitmap dimensions are powers
+ // of 2 but we'd have to deal with size changes. Let's keep this simple
+ const bool canMipMap = Caches::getInstance().extensions().hasNPot();
+
+ // If the texture had mipmap enabled but not anymore,
+ // force a glTexImage2D to discard the mipmap levels
+ const bool resize = !regenerate || bitmap->width() != int(texture->width) ||
+ bitmap->height() != int(texture->height) ||
+ (regenerate && canMipMap && texture->mipMap && !bitmap->hasHardwareMipMap());
+
+ if (!regenerate) {
+ glGenTextures(1, &texture->id);
+ }
+
+ texture->generation = bitmap->getGenerationID();
+ texture->width = bitmap->width();
+ texture->height = bitmap->height();
+
+ bindTexture(texture->id);
+
+ switch (bitmap->colorType()) {
+ case kAlpha_8_SkColorType:
+ uploadSkBitmapToTexture(*bitmap, resize, GL_ALPHA, GL_UNSIGNED_BYTE);
+ texture->blend = true;
+ break;
+ case kRGB_565_SkColorType:
+ uploadSkBitmapToTexture(*bitmap, resize, GL_RGB, GL_UNSIGNED_SHORT_5_6_5);
+ texture->blend = false;
+ break;
+ case kN32_SkColorType:
+ uploadSkBitmapToTexture(*bitmap, resize, GL_RGBA, GL_UNSIGNED_BYTE);
+ // Do this after calling getPixels() to make sure Skia's deferred
+ // decoding happened
+ texture->blend = !bitmap->isOpaque();
+ break;
+ case kARGB_4444_SkColorType:
+ case kIndex_8_SkColorType: {
+ SkBitmap rgbaBitmap;
+ rgbaBitmap.allocPixels(SkImageInfo::MakeN32(texture->width, texture->height,
+ bitmap->alphaType()));
+ rgbaBitmap.eraseColor(0);
+
+ SkCanvas canvas(rgbaBitmap);
+ canvas.drawBitmap(*bitmap, 0.0f, 0.0f, nullptr);
+
+ uploadSkBitmapToTexture(rgbaBitmap, resize, GL_RGBA, GL_UNSIGNED_BYTE);
+ texture->blend = !bitmap->isOpaque();
+ break;
+ }
+ default:
+ ALOGW("Unsupported bitmap colorType: %d", bitmap->colorType());
+ break;
+ }
+
+ if (canMipMap) {
+ texture->mipMap = bitmap->hasHardwareMipMap();
+ if (texture->mipMap) {
+ glGenerateMipmap(GL_TEXTURE_2D);
+ }
+ }
+
+ if (!regenerate) {
+ texture->setFilter(GL_NEAREST);
+ texture->setWrap(GL_CLAMP_TO_EDGE);
+ }
+}
+
TextureState::TextureState()
: mTextureUnit(0) {
glActiveTexture(kTextureUnits[0]);
diff --git a/libs/hwui/renderstate/TextureState.h b/libs/hwui/renderstate/TextureState.h
index d3c014c00bce..3a2b85ae2886 100644
--- a/libs/hwui/renderstate/TextureState.h
+++ b/libs/hwui/renderstate/TextureState.h
@@ -23,9 +23,13 @@
#include <SkXfermode.h>
#include <memory>
+class SkBitmap;
+
namespace android {
namespace uirenderer {
+class Texture;
+
class TextureState {
friend class Caches; // TODO: move to RenderState
public:
@@ -71,6 +75,14 @@ public:
* Clear the cache of bound textures.
*/
void unbindTexture(GLuint texture);
+
+ /**
+ * Generates the texture from a bitmap into the specified texture structure.
+ *
+ * @param regenerate If true, the bitmap data is reuploaded into the texture, but
+ * no new texture is generated.
+ */
+ void generateTexture(const SkBitmap* bitmap, Texture* texture, bool regenerate);
private:
// total number of texture units available for use
static const int kTextureUnitsCount = 4;
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index b74b5088c14f..9dc5b45a7738 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -60,9 +60,10 @@ CanvasContext::CanvasContext(RenderThread& thread, bool translucent,
, mEglManager(thread.eglManager())
, mOpaque(!translucent)
, mAnimationContext(contextFactory->createAnimationContext(mRenderThread.timeLord()))
- , mRootRenderNode(rootRenderNode)
, mJankTracker(thread.timeLord().frameIntervalNanos())
- , mProfiler(mFrames) {
+ , mProfiler(mFrames)
+ , mContentOverdrawProtectionBounds(0, 0, 0, 0) {
+ mRenderNodes.emplace_back(rootRenderNode);
mRenderThread.renderState().registerCanvasContext(this);
mProfiler.setDensity(mRenderThread.mainDisplayInfo().density);
}
@@ -172,7 +173,8 @@ static bool wasSkipped(FrameInfo* info) {
return info && ((*info)[FrameInfoIndex::Flags] & FrameInfoFlags::SkippedFrame);
}
-void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t syncQueued) {
+void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo,
+ int64_t syncQueued, RenderNode* target) {
mRenderThread.removeFrameCallback(this);
// If the previous frame was dropped we don't need to hold onto it, so
@@ -189,7 +191,13 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t sy
info.canvasContext = this;
mAnimationContext->startFrame(info.mode);
- mRootRenderNode->prepareTree(info);
+ for (const sp<RenderNode>& node : mRenderNodes) {
+ // Only the primary target node will be drawn full - all other nodes would get drawn in
+ // real time mode. In case of a window, the primary node is the window content and the other
+ // node(s) are non client / filler nodes.
+ info.mode = (node.get() == target ? TreeInfo::MODE_FULL : TreeInfo::MODE_RT_ONLY);
+ node->prepareTree(info);
+ }
mAnimationContext->runRemainingAnimations(info);
freePrefetechedLayers();
@@ -299,7 +307,95 @@ void CanvasContext::draw() {
dirty.fLeft, dirty.fTop, dirty.fRight, dirty.fBottom, mOpaque);
Rect outBounds;
- mCanvas->drawRenderNode(mRootRenderNode.get(), outBounds);
+ // It there are multiple render nodes, they are as follows:
+ // #0 - backdrop
+ // #1 - content (with - and clipped to - bounds mContentOverdrawProtectionBounds)
+ // #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
+ // backdrop against the content and draw the remaining part of it. It will then crop the content
+ // 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;
+ // If there is no content bounds we ignore the layering as stated above and start with 2.
+ int layer = mContentOverdrawProtectionBounds.isEmpty() ? 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.
+ const RenderProperties& properties = node->properties();
+ Rect targetBounds(properties.getLeft(), properties.getTop(),
+ properties.getRight(), properties.getBottom());
+ // Remember the intersection of the target bounds and the intersection bounds against
+ // which we have to crop the content.
+ backdropBounds.intersect(targetBounds);
+ // Check if we have to draw something on the left side ...
+ if (targetBounds.left < mContentOverdrawProtectionBounds.left) {
+ mCanvas->save(SkCanvas::kClip_SaveFlag);
+ if (mCanvas->clipRect(targetBounds.left, targetBounds.top,
+ mContentOverdrawProtectionBounds.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);
+ mCanvas->restore();
+ }
+ // ... or on the right side ...
+ if (targetBounds.right > mContentOverdrawProtectionBounds.right &&
+ !targetBounds.isEmpty()) {
+ mCanvas->save(SkCanvas::kClip_SaveFlag);
+ if (mCanvas->clipRect(mContentOverdrawProtectionBounds.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);
+ mCanvas->restore();
+ }
+ // ... or at the top ...
+ if (targetBounds.top < mContentOverdrawProtectionBounds.top &&
+ !targetBounds.isEmpty()) {
+ mCanvas->save(SkCanvas::kClip_SaveFlag);
+ if (mCanvas->clipRect(targetBounds.left, targetBounds.top, targetBounds.right,
+ mContentOverdrawProtectionBounds.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);
+ mCanvas->restore();
+ }
+ // ... or at the bottom.
+ if (targetBounds.bottom > mContentOverdrawProtectionBounds.bottom &&
+ !targetBounds.isEmpty()) {
+ mCanvas->save(SkCanvas::kClip_SaveFlag);
+ if (mCanvas->clipRect(targetBounds.left,
+ mContentOverdrawProtectionBounds.bottom, targetBounds.right,
+ targetBounds.bottom, SkRegion::kIntersect_Op)) {
+ mCanvas->drawRenderNode(node.get(), outBounds);
+ }
+ mCanvas->restore();
+ }
+ } 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->drawRenderNode(node.get(), outBounds);
+ }
+ mCanvas->restore();
+ } else { // draw the rest on top at will!
+ mCanvas->drawRenderNode(node.get(), outBounds);
+ }
+ layer++;
+ }
profiler().draw(mCanvas);
@@ -343,7 +439,10 @@ void CanvasContext::doFrame() {
if (CC_UNLIKELY(!mCanvas || mEglSurface == EGL_NO_SURFACE)) {
return;
}
+ prepareAndDraw(nullptr);
+}
+void CanvasContext::prepareAndDraw(RenderNode* node) {
ATRACE_CALL();
int64_t frameInfo[UI_THREAD_FRAME_INFO_SIZE];
@@ -353,7 +452,7 @@ void CanvasContext::doFrame() {
mRenderThread.timeLord().latestVsync());
TreeInfo info(TreeInfo::MODE_RT_ONLY, mRenderThread.renderState());
- prepareTree(info, frameInfo, systemTime(CLOCK_MONOTONIC));
+ prepareTree(info, frameInfo, systemTime(CLOCK_MONOTONIC), node);
if (info.out.canDrawThisFrame) {
draw();
}
@@ -423,7 +522,9 @@ void CanvasContext::destroyHardwareResources() {
stopDrawing();
if (mEglManager.hasEglContext()) {
freePrefetechedLayers();
- mRootRenderNode->destroyHardwareResources();
+ for (const sp<RenderNode>& node : mRenderNodes) {
+ node->destroyHardwareResources();
+ }
Caches& caches = Caches::getInstance();
// Make sure to release all the textures we were owning as there won't
// be another draw
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 6a793203e290..1c3845cac504 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -34,6 +34,7 @@
#include <set>
#include <string>
+#include <vector>
namespace android {
namespace uirenderer {
@@ -77,12 +78,14 @@ public:
void setOpaque(bool opaque);
void makeCurrent();
void processLayerUpdate(DeferredLayerUpdater* layerUpdater);
- void prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t syncQueued);
+ void prepareTree(TreeInfo& info, int64_t* uiFrameInfo,
+ int64_t syncQueued, RenderNode* target);
void draw();
void destroy();
// IFrameCallback, Chroreographer-driven frame callback entry point
virtual void doFrame() override;
+ void prepareAndDraw(RenderNode* node);
void buildLayer(RenderNode* node);
bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap);
@@ -113,6 +116,20 @@ public:
void serializeDisplayListTree();
+ void addRenderNode(RenderNode* node, bool placeFront) {
+ int pos = placeFront ? 0 : static_cast<int>(mRenderNodes.size());
+ mRenderNodes.emplace( mRenderNodes.begin() + pos, node);
+ }
+
+ void removeRenderNode(RenderNode* node) {
+ mRenderNodes.erase(std::remove(mRenderNodes.begin(), mRenderNodes.end(), node),
+ mRenderNodes.end());
+ }
+
+ void setContentOverdrawProtectionBounds(int left, int top, int right, int bottom) {
+ mContentOverdrawProtectionBounds.set(left, top, right, bottom);
+ }
+
private:
friend class RegisterFrameCallbackTask;
// TODO: Replace with something better for layer & other GL object
@@ -138,7 +155,7 @@ private:
DamageAccumulator mDamageAccumulator;
std::unique_ptr<AnimationContext> mAnimationContext;
- const sp<RenderNode> mRootRenderNode;
+ std::vector< sp<RenderNode> > mRenderNodes;
FrameInfo* mCurrentFrameInfo = nullptr;
// Ring buffer large enough for 2 seconds worth of frames
@@ -148,6 +165,9 @@ private:
FrameInfoVisualizer mProfiler;
std::set<RenderNode*> mPrefetechedLayers;
+
+ // Stores the bounds of the main content.
+ Rect mContentOverdrawProtectionBounds;
};
} /* namespace renderthread */
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index 198906ca845e..a47c9ecf8b31 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -38,9 +38,11 @@ DrawFrameTask::DrawFrameTask()
DrawFrameTask::~DrawFrameTask() {
}
-void DrawFrameTask::setContext(RenderThread* thread, CanvasContext* context) {
+void DrawFrameTask::setContext(RenderThread* thread, CanvasContext* context,
+ RenderNode* targetNode) {
mRenderThread = thread;
mContext = context;
+ mTargetNode = targetNode;
}
void DrawFrameTask::pushLayerUpdate(DeferredLayerUpdater* layer) {
@@ -118,7 +120,7 @@ bool DrawFrameTask::syncFrameState(TreeInfo& info) {
mContext->processLayerUpdate(mLayers[i].get());
}
mLayers.clear();
- mContext->prepareTree(info, mFrameInfo, mSyncQueued);
+ mContext->prepareTree(info, mFrameInfo, mSyncQueued, mTargetNode);
// This is after the prepareTree so that any pending operations
// (RenderNode tree state, prefetched layers, etc...) will be flushed.
diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h
index ebefcba9f6a5..68ee897e3b8e 100644
--- a/libs/hwui/renderthread/DrawFrameTask.h
+++ b/libs/hwui/renderthread/DrawFrameTask.h
@@ -57,7 +57,7 @@ public:
DrawFrameTask();
virtual ~DrawFrameTask();
- void setContext(RenderThread* thread, CanvasContext* context);
+ void setContext(RenderThread* thread, CanvasContext* context, RenderNode* targetNode);
void pushLayerUpdate(DeferredLayerUpdater* layer);
void removeLayerUpdate(DeferredLayerUpdater* layer);
@@ -78,6 +78,7 @@ private:
RenderThread* mRenderThread;
CanvasContext* mContext;
+ RenderNode* mTargetNode = nullptr;
/*********************************************
* Single frame data
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index d2ce49f800fc..c9b9637dd52e 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -20,6 +20,7 @@
#include "Properties.h"
#include "RenderThread.h"
#include "renderstate/RenderState.h"
+#include "utils/StringUtils.h"
#include <cutils/log.h>
#include <cutils/properties.h>
@@ -133,12 +134,9 @@ void EglManager::initialize() {
}
void EglManager::initExtensions() {
- std::string extensions(eglQueryString(mEglDisplay, EGL_EXTENSIONS));
- auto has = [&](const char* ext) {
- return extensions.find(ext) != std::string::npos;
- };
- EglExtensions.bufferAge = has("EGL_EXT_buffer_age");
- EglExtensions.setDamage = has("EGL_KHR_partial_update");
+ StringCollection extensions(eglQueryString(mEglDisplay, EGL_EXTENSIONS));
+ EglExtensions.bufferAge = extensions.has("EGL_EXT_buffer_age");
+ EglExtensions.setDamage = extensions.has("EGL_KHR_partial_update");
}
bool EglManager::hasEglContext() {
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index b8388116ff80..f43a769890a4 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -74,7 +74,7 @@ RenderProxy::RenderProxy(bool translucent, RenderNode* rootRenderNode, IContextF
args->thread = &mRenderThread;
args->contextFactory = contextFactory;
mContext = (CanvasContext*) postAndWait(task);
- mDrawFrameTask.setContext(&mRenderThread, mContext);
+ mDrawFrameTask.setContext(&mRenderThread, mContext, rootRenderNode);
}
RenderProxy::~RenderProxy() {
@@ -91,7 +91,7 @@ void RenderProxy::destroyContext() {
SETUP_TASK(destroyContext);
args->context = mContext;
mContext = nullptr;
- mDrawFrameTask.setContext(nullptr, nullptr);
+ mDrawFrameTask.setContext(nullptr, nullptr, nullptr);
// This is also a fence as we need to be certain that there are no
// outstanding mDrawFrame tasks posted before it is destroyed
postAndWait(task);
@@ -461,7 +461,8 @@ void RenderProxy::dumpGraphicsMemory(int fd) {
staticPostAndWait(task);
}
-CREATE_BRIDGE4(setTextureAtlas, RenderThread* thread, GraphicBuffer* buffer, int64_t* map, size_t size) {
+CREATE_BRIDGE4(setTextureAtlas, RenderThread* thread, GraphicBuffer* buffer, int64_t* map,
+ size_t size) {
CanvasContext::setTextureAtlas(*args->thread, args->buffer, args->map, args->size);
args->buffer->decStrong(nullptr);
return nullptr;
@@ -490,6 +491,61 @@ void RenderProxy::setProcessStatsBuffer(int fd) {
post(task);
}
+CREATE_BRIDGE3(addRenderNode, CanvasContext* context, RenderNode* node, bool placeFront) {
+ args->context->addRenderNode(args->node, args->placeFront);
+ return nullptr;
+}
+
+void RenderProxy::addRenderNode(RenderNode* node, bool placeFront) {
+ SETUP_TASK(addRenderNode);
+ args->context = mContext;
+ args->node = node;
+ args->placeFront = placeFront;
+ post(task);
+}
+
+CREATE_BRIDGE2(removeRenderNode, CanvasContext* context, RenderNode* node) {
+ args->context->removeRenderNode(args->node);
+ return nullptr;
+}
+
+void RenderProxy::removeRenderNode(RenderNode* node) {
+ SETUP_TASK(removeRenderNode);
+ args->context = mContext;
+ args->node = node;
+ post(task);
+}
+
+CREATE_BRIDGE2(drawRenderNode, CanvasContext* context, RenderNode* node) {
+ args->context->prepareAndDraw(args->node);
+ return nullptr;
+}
+
+void RenderProxy::drawRenderNode(RenderNode* node) {
+ SETUP_TASK(drawRenderNode);
+ args->context = mContext;
+ args->node = node;
+ // Be pseudo-thread-safe and don't use any member variables
+ staticPostAndWait(task);
+}
+
+CREATE_BRIDGE5(setContentOverdrawProtectionBounds, CanvasContext* context, int left, int top,
+ int right, int bottom) {
+ args->context->setContentOverdrawProtectionBounds(args->left, args->top, args->right,
+ args->bottom);
+ return nullptr;
+}
+
+void RenderProxy::setContentOverdrawProtectionBounds(int left, int top, int right, int bottom) {
+ SETUP_TASK(setContentOverdrawProtectionBounds);
+ args->context = mContext;
+ args->left = left;
+ args->top = top;
+ args->right = right;
+ args->bottom = bottom;
+ staticPostAndWait(task);
+}
+
CREATE_BRIDGE1(serializeDisplayListTree, CanvasContext* context) {
args->context->serializeDisplayListTree();
return nullptr;
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index e7356dbb0373..046f24ac3f81 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -106,6 +106,11 @@ public:
ANDROID_API void serializeDisplayListTree();
+ 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);
+
private:
RenderThread& mRenderThread;
CanvasContext* mContext;
diff --git a/libs/hwui/unit_tests/StringUtilsTests.cpp b/libs/hwui/unit_tests/StringUtilsTests.cpp
new file mode 100644
index 000000000000..5174ae99e71e
--- /dev/null
+++ b/libs/hwui/unit_tests/StringUtilsTests.cpp
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include "utils/StringUtils.h"
+
+namespace android {
+namespace uirenderer {
+
+TEST(StringUtils, simpleBuildSet) {
+ StringCollection collection("a b c");
+
+ EXPECT_TRUE(collection.has("a"));
+ EXPECT_TRUE(collection.has("b"));
+ EXPECT_TRUE(collection.has("c"));
+ EXPECT_FALSE(collection.has("d"));
+}
+
+TEST(StringUtils, advancedBuildSet) {
+ StringCollection collection("GL_ext1 GL_ext2 GL_ext3");
+
+ EXPECT_TRUE(collection.has("GL_ext1"));
+ EXPECT_FALSE(collection.has("GL_ext")); // string present, but not in list
+}
+
+};
+};
diff --git a/libs/hwui/utils/StringUtils.cpp b/libs/hwui/utils/StringUtils.cpp
new file mode 100644
index 000000000000..a1df0e7966a9
--- /dev/null
+++ b/libs/hwui/utils/StringUtils.cpp
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+#include "StringUtils.h"
+
+namespace android {
+namespace uirenderer {
+
+StringCollection::StringCollection(const char* spacedList) {
+ const char* current = spacedList;
+ const char* head = current;
+ do {
+ head = strchr(current, ' ');
+ std::string s(current, head ? head - current : strlen(current));
+ if (s.length()) {
+ mSet.insert(s);
+ }
+ current = head + 1;
+ } while (head);
+}
+
+bool StringCollection::has(const char* s) {
+ return mSet.find(std::string(s)) != mSet.end();
+}
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/utils/StringUtils.h b/libs/hwui/utils/StringUtils.h
new file mode 100644
index 000000000000..ef2a6d5c031a
--- /dev/null
+++ b/libs/hwui/utils/StringUtils.h
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+#ifndef STRING_UTILS_H
+#define STRING_UTILS_H
+
+#include <string>
+#include <unordered_set>
+
+namespace android {
+namespace uirenderer {
+
+class StringCollection {
+public:
+ StringCollection(const char* spacedList);
+ bool has(const char* string);
+private:
+ std::unordered_set<std::string> mSet;
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif /* GLUTILS_H */
diff --git a/media/java/android/media/midi/MidiManager.java b/media/java/android/media/midi/MidiManager.java
index e72bdb446a65..266b0d97cb53 100644
--- a/media/java/android/media/midi/MidiManager.java
+++ b/media/java/android/media/midi/MidiManager.java
@@ -169,6 +169,13 @@ public final class MidiManager {
/**
* Registers a callback to receive notifications when MIDI devices are added and removed.
*
+ * The {@link DeviceCallback#onDeviceStatusChanged} method will be called immediately
+ * for any devices that have open ports. This allows applications to know which input
+ * ports are already in use and, therefore, unavailable.
+ *
+ * Applications should call {@link #getDevices} before registering the callback
+ * to get a list of devices already added.
+ *
* @param callback a {@link DeviceCallback} for MIDI device notifications
* @param handler The {@link android.os.Handler Handler} that will be used for delivering the
* device notifications. If handler is null, then the thread used for the
diff --git a/media/jni/android_media_AmrInputStream.cpp b/media/jni/android_media_AmrInputStream.cpp
index afb5d5cbba74..b56a3641ac9f 100644
--- a/media/jni/android_media_AmrInputStream.cpp
+++ b/media/jni/android_media_AmrInputStream.cpp
@@ -119,7 +119,7 @@ static void android_media_AmrInputStream_GsmAmrEncoderDelete
// ----------------------------------------------------------------------------
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
{"GsmAmrEncoderNew", "()J", (void*)android_media_AmrInputStream_GsmAmrEncoderNew},
{"GsmAmrEncoderInitialize", "(J)V", (void*)android_media_AmrInputStream_GsmAmrEncoderInitialize},
{"GsmAmrEncoderEncode", "(J[BI[BI)I", (void*)android_media_AmrInputStream_GsmAmrEncoderEncode},
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index 0034b07762a8..3ffdb17f4ec0 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -1253,7 +1253,7 @@ static jint Image_getFormat(JNIEnv* env, jobject thiz, jint readerFormat)
// ----------------------------------------------------------------------------
-static JNINativeMethod gImageReaderMethods[] = {
+static const JNINativeMethod gImageReaderMethods[] = {
{"nativeClassInit", "()V", (void*)ImageReader_classInit },
{"nativeInit", "(Ljava/lang/Object;IIII)V", (void*)ImageReader_init },
{"nativeClose", "()V", (void*)ImageReader_close },
@@ -1263,7 +1263,7 @@ static JNINativeMethod gImageReaderMethods[] = {
{"nativeDetachImage", "(Landroid/media/Image;)I", (void*)ImageReader_detachImage },
};
-static JNINativeMethod gImageMethods[] = {
+static const JNINativeMethod gImageMethods[] = {
{"nativeImageGetBuffer", "(II)Ljava/nio/ByteBuffer;", (void*)Image_getByteBuffer },
{"nativeCreatePlane", "(II)Landroid/media/ImageReader$SurfaceImage$SurfacePlane;",
(void*)Image_createSurfacePlane },
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 93a44261281b..e8f680f6a36c 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -1798,7 +1798,7 @@ static void android_media_MediaCodec_native_finalize(
android_media_MediaCodec_release(env, thiz);
}
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
{ "native_release", "()V", (void *)android_media_MediaCodec_release },
{ "native_reset", "()V", (void *)android_media_MediaCodec_reset },
diff --git a/media/jni/android_media_MediaCodecList.cpp b/media/jni/android_media_MediaCodecList.cpp
index 82dd48dffeae..de9bf1f528af 100644
--- a/media/jni/android_media_MediaCodecList.cpp
+++ b/media/jni/android_media_MediaCodecList.cpp
@@ -286,7 +286,7 @@ static jobject android_media_MediaCodecList_getGlobalSettings(JNIEnv *env, jobje
static void android_media_MediaCodecList_native_init(JNIEnv* /* env */) {
}
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
{ "native_getCodecCount", "()I", (void *)android_media_MediaCodecList_getCodecCount },
{ "getCodecName", "(I)Ljava/lang/String;",
(void *)android_media_MediaCodecList_getCodecName },
diff --git a/media/jni/android_media_MediaCrypto.cpp b/media/jni/android_media_MediaCrypto.cpp
index d7968d225ab2..e414f4838583 100644
--- a/media/jni/android_media_MediaCrypto.cpp
+++ b/media/jni/android_media_MediaCrypto.cpp
@@ -316,7 +316,7 @@ static void android_media_MediaCrypto_setMediaDrmSession(
}
}
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
{ "release", "()V", (void *)android_media_MediaCrypto_release },
{ "native_init", "()V", (void *)android_media_MediaCrypto_native_init },
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index 9ec0312d0f2a..275de1ad5ccb 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -1455,7 +1455,7 @@ static jbyteArray android_media_MediaDrm_signRSANative(
}
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
{ "release", "()V", (void *)android_media_MediaDrm_release },
{ "native_init", "()V", (void *)android_media_MediaDrm_native_init },
diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp
index 4e9b72685223..96c12dd8665b 100644
--- a/media/jni/android_media_MediaExtractor.cpp
+++ b/media/jni/android_media_MediaExtractor.cpp
@@ -769,7 +769,7 @@ static void android_media_MediaExtractor_native_finalize(
android_media_MediaExtractor_release(env, thiz);
}
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
{ "release", "()V", (void *)android_media_MediaExtractor_release },
{ "getTrackCount", "()I", (void *)android_media_MediaExtractor_getTrackCount },
diff --git a/media/jni/android_media_MediaHTTPConnection.cpp b/media/jni/android_media_MediaHTTPConnection.cpp
index 393003d98462..fa0b43fedcef 100644
--- a/media/jni/android_media_MediaHTTPConnection.cpp
+++ b/media/jni/android_media_MediaHTTPConnection.cpp
@@ -154,7 +154,7 @@ static jint android_media_MediaHTTPConnection_native_readAt(
return n;
}
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
{ "native_getIMemory", "()Landroid/os/IBinder;",
(void *)android_media_MediaHTTPConnection_native_getIMemory },
diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp
index 59fb6d6f6859..f4e940d6cb21 100644
--- a/media/jni/android_media_MediaMetadataRetriever.cpp
+++ b/media/jni/android_media_MediaMetadataRetriever.cpp
@@ -467,7 +467,7 @@ static void android_media_MediaMetadataRetriever_native_setup(JNIEnv *env, jobje
}
// JNI mapping between Java methods and native methods
-static JNINativeMethod nativeMethods[] = {
+static const JNINativeMethod nativeMethods[] = {
{
"_setDataSource",
"(Landroid/os/IBinder;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V",
diff --git a/media/jni/android_media_MediaMuxer.cpp b/media/jni/android_media_MediaMuxer.cpp
index ecb2ac8a61e8..216624e96ad2 100644
--- a/media/jni/android_media_MediaMuxer.cpp
+++ b/media/jni/android_media_MediaMuxer.cpp
@@ -219,7 +219,7 @@ static void android_media_MediaMuxer_native_release(
}
}
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
{ "nativeAddTrack", "(J[Ljava/lang/String;[Ljava/lang/Object;)I",
(void *)android_media_MediaMuxer_addTrack },
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index d8041f4bff04..be3672968398 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -1033,7 +1033,7 @@ android_media_MediaPlayer_setNextMediaPlayer(JNIEnv *env, jobject thiz, jobject
// ----------------------------------------------------------------------------
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
{
"nativeSetDataSource",
"(Landroid/os/IBinder;Ljava/lang/String;[Ljava/lang/String;"
diff --git a/media/jni/android_media_MediaProfiles.cpp b/media/jni/android_media_MediaProfiles.cpp
index ca9db91c5eed..580004304170 100644
--- a/media/jni/android_media_MediaProfiles.cpp
+++ b/media/jni/android_media_MediaProfiles.cpp
@@ -301,7 +301,7 @@ android_media_MediaProfiles_native_get_image_encoding_quality_level(JNIEnv *env,
}
return static_cast<jint>(levels[index]);
}
-static JNINativeMethod gMethodsForEncoderCapabilitiesClass[] = {
+static const JNINativeMethod gMethodsForEncoderCapabilitiesClass[] = {
{"native_init", "()V", (void *)android_media_MediaProfiles_native_init},
{"native_get_num_file_formats", "()I", (void *)android_media_MediaProfiles_native_get_num_file_formats},
{"native_get_file_format", "(I)I", (void *)android_media_MediaProfiles_native_get_file_format},
@@ -315,7 +315,7 @@ static JNINativeMethod gMethodsForEncoderCapabilitiesClass[] = {
(void *)android_media_MediaProfiles_native_get_audio_encoder_cap},
};
-static JNINativeMethod gMethodsForCamcorderProfileClass[] = {
+static const JNINativeMethod gMethodsForCamcorderProfileClass[] = {
{"native_init", "()V", (void *)android_media_MediaProfiles_native_init},
{"native_get_camcorder_profile", "(II)Landroid/media/CamcorderProfile;",
(void *)android_media_MediaProfiles_native_get_camcorder_profile},
@@ -323,7 +323,7 @@ static JNINativeMethod gMethodsForCamcorderProfileClass[] = {
(void *)android_media_MediaProfiles_native_has_camcorder_profile},
};
-static JNINativeMethod gMethodsForDecoderCapabilitiesClass[] = {
+static const JNINativeMethod gMethodsForDecoderCapabilitiesClass[] = {
{"native_init", "()V", (void *)android_media_MediaProfiles_native_init},
{"native_get_num_video_decoders", "()I", (void *)android_media_MediaProfiles_native_get_num_video_decoders},
{"native_get_num_audio_decoders", "()I", (void *)android_media_MediaProfiles_native_get_num_audio_decoders},
@@ -331,7 +331,7 @@ static JNINativeMethod gMethodsForDecoderCapabilitiesClass[] = {
{"native_get_audio_decoder_type", "(I)I", (void *)android_media_MediaProfiles_native_get_audio_decoder_type},
};
-static JNINativeMethod gMethodsForCameraProfileClass[] = {
+static const JNINativeMethod gMethodsForCameraProfileClass[] = {
{"native_init", "()V", (void *)android_media_MediaProfiles_native_init},
{"native_get_num_image_encoding_quality_levels",
"(I)I", (void *)android_media_MediaProfiles_native_get_num_image_encoding_quality_levels},
diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp
index f60af63306ba..e05b3483aadc 100644
--- a/media/jni/android_media_MediaRecorder.cpp
+++ b/media/jni/android_media_MediaRecorder.cpp
@@ -510,7 +510,7 @@ void android_media_MediaRecorder_setInputSurface(
// ----------------------------------------------------------------------------
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
{"setCamera", "(Landroid/hardware/Camera;)V", (void *)android_media_MediaRecorder_setCamera},
{"setVideoSource", "(I)V", (void *)android_media_MediaRecorder_setVideoSource},
{"setAudioSource", "(I)V", (void *)android_media_MediaRecorder_setAudioSource},
diff --git a/media/jni/android_media_MediaScanner.cpp b/media/jni/android_media_MediaScanner.cpp
index 1a9384e6b2c8..0f3c61f53a2c 100644
--- a/media/jni/android_media_MediaScanner.cpp
+++ b/media/jni/android_media_MediaScanner.cpp
@@ -412,7 +412,7 @@ android_media_MediaScanner_native_finalize(JNIEnv *env, jobject thiz)
setNativeScanner_l(env, thiz, 0);
}
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
{
"processDirectory",
"(Ljava/lang/String;Landroid/media/MediaScannerClient;)V",
diff --git a/media/jni/android_media_ResampleInputStream.cpp b/media/jni/android_media_ResampleInputStream.cpp
index 1549a301772a..d06baa57071d 100644
--- a/media/jni/android_media_ResampleInputStream.cpp
+++ b/media/jni/android_media_ResampleInputStream.cpp
@@ -107,7 +107,7 @@ static void android_media_ResampleInputStream_fir21(JNIEnv *env, jclass /* clazz
// ----------------------------------------------------------------------------
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
{"fir21", "([BI[BII)V", (void*)android_media_ResampleInputStream_fir21},
};
diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp
index 713f28ce5684..ec2f98a4c9b4 100644
--- a/media/jni/android_mtp_MtpDatabase.cpp
+++ b/media/jni/android_mtp_MtpDatabase.cpp
@@ -1173,12 +1173,12 @@ android_mtp_MtpPropertyGroup_format_date_time(JNIEnv *env, jobject /*thiz*/, jlo
// ----------------------------------------------------------------------------
-static JNINativeMethod gMtpDatabaseMethods[] = {
+static const JNINativeMethod gMtpDatabaseMethods[] = {
{"native_setup", "()V", (void *)android_mtp_MtpDatabase_setup},
{"native_finalize", "()V", (void *)android_mtp_MtpDatabase_finalize},
};
-static JNINativeMethod gMtpPropertyGroupMethods[] = {
+static const JNINativeMethod gMtpPropertyGroupMethods[] = {
{"format_date_time", "(J)Ljava/lang/String;",
(void *)android_mtp_MtpPropertyGroup_format_date_time},
};
diff --git a/media/jni/android_mtp_MtpDevice.cpp b/media/jni/android_mtp_MtpDevice.cpp
index 2a46ee72e50c..f11329c7b258 100644
--- a/media/jni/android_mtp_MtpDevice.cpp
+++ b/media/jni/android_mtp_MtpDevice.cpp
@@ -490,7 +490,7 @@ android_mtp_MtpDevice_send_object_info(JNIEnv *env, jobject thiz, jobject info)
// ----------------------------------------------------------------------------
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
{"native_open", "(Ljava/lang/String;I)Z",
(void *)android_mtp_MtpDevice_open},
{"native_close", "()V", (void *)android_mtp_MtpDevice_close},
diff --git a/media/jni/android_mtp_MtpServer.cpp b/media/jni/android_mtp_MtpServer.cpp
index 2ce2a904e0f0..d13187c39846 100644
--- a/media/jni/android_mtp_MtpServer.cpp
+++ b/media/jni/android_mtp_MtpServer.cpp
@@ -179,7 +179,7 @@ android_mtp_MtpServer_remove_storage(JNIEnv *env, jobject thiz, jint storageId)
// ----------------------------------------------------------------------------
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
{"native_setup", "(Landroid/mtp/MtpDatabase;Z)V",
(void *)android_mtp_MtpServer_setup},
{"native_run", "()V", (void *)android_mtp_MtpServer_run},
diff --git a/media/jni/audioeffect/android_media_AudioEffect.cpp b/media/jni/audioeffect/android_media_AudioEffect.cpp
index aba4bbeb1e70..fa6913573add 100644
--- a/media/jni/audioeffect/android_media_AudioEffect.cpp
+++ b/media/jni/audioeffect/android_media_AudioEffect.cpp
@@ -879,7 +879,7 @@ android_media_AudioEffect_native_queryPreProcessings(JNIEnv *env, jclass clazz _
// ----------------------------------------------------------------------------
// Dalvik VM type signatures
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
{"native_init", "()V", (void *)android_media_AudioEffect_native_init},
{"native_setup", "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;II[I[Ljava/lang/Object;Ljava/lang/String;)I",
(void *)android_media_AudioEffect_native_setup},
diff --git a/media/jni/audioeffect/android_media_Visualizer.cpp b/media/jni/audioeffect/android_media_Visualizer.cpp
index 05570195752b..3d3adba609c0 100644
--- a/media/jni/audioeffect/android_media_Visualizer.cpp
+++ b/media/jni/audioeffect/android_media_Visualizer.cpp
@@ -677,7 +677,7 @@ android_media_setPeriodicCapture(JNIEnv *env, jobject thiz, jint rate, jboolean
// ----------------------------------------------------------------------------
// Dalvik VM type signatures
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
{"native_init", "()V", (void *)android_media_visualizer_native_init},
{"native_setup", "(Ljava/lang/Object;I[ILjava/lang/String;)I",
(void *)android_media_visualizer_native_setup},
diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp
index a705bcc37406..090be88561c4 100644
--- a/media/jni/soundpool/SoundPool.cpp
+++ b/media/jni/soundpool/SoundPool.cpp
@@ -589,6 +589,9 @@ static status_t decode(int fd, int64_t offset, int64_t length,
ALOGV("format changed to: %s", AMediaFormat_toString(format));
} else if (status == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
ALOGV("no output buffer right now");
+ } else if (status <= AMEDIA_ERROR_BASE) {
+ ALOGE("decode error: %d", status);
+ break;
} else {
ALOGV("unexpected info code: %d", status);
}
diff --git a/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java b/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java
index e6d59e4fb141..444705cfc79f 100644
--- a/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java
+++ b/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java
@@ -147,14 +147,22 @@ public final class BluetoothMidiDevice {
// switch to receiving notifications after initial characteristic read
mBluetoothGatt.setCharacteristicNotification(characteristic, true);
+ // Use writeType that requests acknowledgement.
+ // This improves compatibility with various BLE-MIDI devices.
+ int originalWriteType = characteristic.getWriteType();
+ characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
+
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
CLIENT_CHARACTERISTIC_CONFIG);
if (descriptor != null) {
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
- mBluetoothGatt.writeDescriptor(descriptor);
+ boolean result = mBluetoothGatt.writeDescriptor(descriptor);
+ Log.d(TAG, "writeDescriptor returned " + result);
} else {
Log.e(TAG, "No CLIENT_CHARACTERISTIC_CONFIG for device " + mBluetoothDevice);
}
+
+ characteristic.setWriteType(originalWriteType);
}
@Override
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/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
index 0fe5509b95ce..abb464eb3a67 100644
--- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
+++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
@@ -76,8 +76,9 @@ public class CaptivePortalLoginActivity extends Activity {
String server = Settings.Global.getString(getContentResolver(), "captive_portal_server");
if (server == null) server = DEFAULT_SERVER;
mCm = ConnectivityManager.from(this);
+ String url = getIntent().getStringExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_URL);
try {
- mURL = new URL("http", server, "/generate_204");
+ mURL = url != null ? new URL(url) : new URL("http", server, "/generate_204");
} catch (MalformedURLException e) {
// System misconfigured, bail out in a way that at least provides network access.
Log.e(TAG, "Invalid captive portal URL, server=" + server);
diff --git a/packages/DocumentsUI/AndroidManifest.xml b/packages/DocumentsUI/AndroidManifest.xml
index 97bc8fd4d1f4..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"
@@ -35,11 +36,6 @@
<action android:name="android.intent.action.OPEN_DOCUMENT_TREE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
- <intent-filter>
- <action android:name="android.provider.action.BROWSE_DOCUMENT_ROOT" />
- <category android:name="android.intent.category.DEFAULT" />
- <data android:mimeType="vnd.android.document/root" />
- </intent-filter>
</activity>
<activity
@@ -54,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">
@@ -65,6 +61,22 @@
</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" />
+ <data android:mimeType="vnd.android.document/root" />
+ </intent-filter>
+ </activity>
+
<provider
android:name=".RecentsProvider"
android:authorities="com.android.documentsui.recents"
diff --git a/packages/DocumentsUI/res/color/item_doc_grid_overlay.xml b/packages/DocumentsUI/res/color/item_doc_grid_overlay.xml
index 6959c65e2d3a..6dcbb38cb950 100644
--- a/packages/DocumentsUI/res/color/item_doc_grid_overlay.xml
+++ b/packages/DocumentsUI/res/color/item_doc_grid_overlay.xml
@@ -17,7 +17,8 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_activated="true"
- android:color="?android:attr/colorControlHighlight" />
+ android:color="?android:attr/colorAccent"
+ android:alpha="0.1" />
<item
android:state_enabled="false"
android:color="?android:attr/colorBackground"
diff --git a/packages/DocumentsUI/res/drawable/progress_indeterminate_horizontal_material_trimmed.xml b/packages/DocumentsUI/res/drawable/progress_indeterminate_horizontal_material_trimmed.xml
new file mode 100644
index 000000000000..070b9a10351c
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable/progress_indeterminate_horizontal_material_trimmed.xml
@@ -0,0 +1,28 @@
+<?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.
+-->
+
+<!-- Variant of progress_indeterminate_horizontal_material in frameworks/base/core/res, which
+ draws the whole height of the progress bar instead having blank space above and below the
+ bar. -->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:drawable="@drawable/vector_drawable_progress_indeterminate_horizontal_trimmed" >
+ <target
+ android:name="rect2_grp"
+ android:animation="@*android:anim/progress_indeterminate_horizontal_rect2" />
+ <target
+ android:name="rect1_grp"
+ android:animation="@*android:anim/progress_indeterminate_horizontal_rect1" />
+</animated-vector>
diff --git a/packages/DocumentsUI/res/drawable/vector_drawable_progress_indeterminate_horizontal_trimmed.xml b/packages/DocumentsUI/res/drawable/vector_drawable_progress_indeterminate_horizontal_trimmed.xml
new file mode 100644
index 000000000000..39e3a3738e28
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable/vector_drawable_progress_indeterminate_horizontal_trimmed.xml
@@ -0,0 +1,53 @@
+<?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.
+-->
+
+<!-- Variant of vector_drawable_progress_indeterminate_horizontal in frameworks/base/core/res, which
+ draws the whole height of the progress bar instead having blank space above and below the
+ bar. -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="10dp"
+ android:width="360dp"
+ android:viewportHeight="10"
+ android:viewportWidth="360" >
+ <group
+ android:name="progress_group"
+ android:translateX="180"
+ android:translateY="5" >
+ <path
+ android:name="background_track"
+ android:pathData="M -180.0,-5.0 l 360.0,0 l 0,10.0 l -360.0,0 Z"
+ android:fillColor="?android:attr/colorControlActivated"
+ android:fillAlpha="?android:attr/disabledAlpha"/>
+ <group
+ android:name="rect2_grp"
+ android:translateX="-197.60001"
+ android:scaleX="0.1" >
+ <path
+ android:name="rect2"
+ android:pathData="M -144.0,-5.0 l 288.0,0 l 0,10.0 l -288.0,0 Z"
+ android:fillColor="?android:attr/colorControlActivated" />
+ </group>
+ <group
+ android:name="rect1_grp"
+ android:translateX="-522.59998"
+ android:scaleX="0.1" >
+ <path
+ android:name="rect1"
+ android:pathData="M -144.0,-5.0 l 288.0,0 l 0,10.0 l -288.0,0 Z"
+ android:fillColor="?android:attr/colorControlActivated" />
+ </group>
+ </group>
+</vector>
diff --git a/packages/DocumentsUI/res/layout/directory_cluster.xml b/packages/DocumentsUI/res/layout/directory_cluster.xml
index e47e1960563c..8245e53097cd 100644
--- a/packages/DocumentsUI/res/layout/directory_cluster.xml
+++ b/packages/DocumentsUI/res/layout/directory_cluster.xml
@@ -18,6 +18,13 @@
android:layout_height="match_parent"
android:orientation="vertical">
+ <FrameLayout
+ android:id="@+id/container_message_bar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:elevation="8dp"
+ android:background="@color/material_grey_50"/>
+
<com.android.documentsui.DirectoryContainerView
android:id="@+id/container_directory"
android:layout_width="match_parent"
diff --git a/packages/DocumentsUI/res/layout/fragment_directory.xml b/packages/DocumentsUI/res/layout/fragment_directory.xml
index 7aff497ccb44..45cb34db54e0 100644
--- a/packages/DocumentsUI/res/layout/fragment_directory.xml
+++ b/packages/DocumentsUI/res/layout/fragment_directory.xml
@@ -17,35 +17,70 @@
<com.android.documentsui.DirectoryView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:background="@color/material_grey_50">
+ android:background="@color/material_grey_50"
+ android:orientation="vertical"
+ android:animateLayoutChanges="true">
- <TextView
+ <ProgressBar
+ android:id="@+id/progressbar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:indeterminate="true"
+ style="@style/TrimmedHorizontalProgressBar"
+ android:visibility="gone"/>
+
+ <FrameLayout
+ android:id="@+id/container_message_bar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:elevation="8dp"
+ android:background="@color/material_grey_50"
+ android:visibility="gone"/>
+
+ <!-- The empty directory view -->
+ <LinearLayout
android:id="@android:id/empty"
+ android:gravity="center"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:gravity="center"
- android:text="@string/empty"
- android:visibility="gone"
- style="@android:style/TextAppearance.Material.Subhead" />
+ android:orientation="vertical"
+ android:visibility="gone">
+
+ <TextView
+ android:id="@+id/message"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/empty"
+ style="@android:style/TextAppearance.Material.Subhead" />
- <!-- The 'list' view is still used for RecentsCreateFragment -->
- <ListView
- android:id="@+id/list"
+ <Button
+ android:id="@+id/button_retry"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/button_retry"
+ style="?android:attr/buttonBarPositiveButtonStyle" />
+
+ </LinearLayout>
+
+ <!-- This FrameLayout works around b/24189541 -->
+ <FrameLayout
android:layout_width="match_parent"
- android:layout_height="match_parent" />
+ android:layout_height="match_parent">
- <android.support.v7.widget.RecyclerView
- android:id="@+id/recyclerView"
- android:scrollbars="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:paddingStart="@dimen/grid_padding_horiz"
- android:paddingEnd="@dimen/grid_padding_horiz"
- android:paddingTop="@dimen/grid_padding_vert"
- android:paddingBottom="@dimen/grid_padding_vert"
- android:clipToPadding="false"
- android:scrollbarStyle="outsideOverlay"
- android:drawSelectorOnTop="true"
- android:background="@color/directory_background" />
+ <android.support.v7.widget.RecyclerView
+ android:id="@+id/recyclerView"
+ android:scrollbars="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingStart="@dimen/grid_padding_horiz"
+ android:paddingEnd="@dimen/grid_padding_horiz"
+ android:paddingTop="@dimen/grid_padding_vert"
+ android:paddingBottom="@dimen/grid_padding_vert"
+ android:clipToPadding="false"
+ android:scrollbarStyle="outsideOverlay"
+ android:drawSelectorOnTop="true"
+ android:background="@color/directory_background" />
+
+ </FrameLayout>
</com.android.documentsui.DirectoryView>
diff --git a/packages/DocumentsUI/res/layout/fragment_message_bar.xml b/packages/DocumentsUI/res/layout/fragment_message_bar.xml
new file mode 100644
index 000000000000..47e4e770b15c
--- /dev/null
+++ b/packages/DocumentsUI/res/layout/fragment_message_bar.xml
@@ -0,0 +1,100 @@
+<?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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:animateLayoutChanges="true"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:minHeight="?android:attr/listPreferredItemHeightSmall"
+ android:orientation="vertical"
+ android:paddingLeft="@dimen/list_item_padding"
+ android:paddingRight="@dimen/list_item_padding"
+ android:paddingTop="@dimen/list_item_padding">
+
+ <LinearLayout
+ android:id="@+id/container_info"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:orientation="horizontal"
+ android:visibility="gone">
+
+ <FrameLayout
+ android:layout_height="@dimen/icon_size"
+ android:layout_width="@dimen/icon_size">
+
+ <ImageView
+ android:contentDescription="@null"
+ android:id="@+id/icon_info"
+ android:layout_height="match_parent"
+ android:layout_width="wrap_content"
+ android:scaleType="centerInside"/>
+
+ </FrameLayout>
+
+ <TextView
+ android:id="@+id/textview_info"
+ android:layout_gravity="center_vertical"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:selectAllOnFocus="true"/>
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/container_error"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:orientation="horizontal"
+ android:visibility="gone">
+
+ <FrameLayout
+ android:layout_height="@dimen/icon_size"
+ android:layout_width="@dimen/icon_size">
+
+ <ImageView
+ android:contentDescription="@null"
+ android:id="@+id/icon_error"
+ android:layout_height="match_parent"
+ android:layout_width="wrap_content"
+ android:scaleType="centerInside"/>
+
+ </FrameLayout>
+
+ <TextView
+ android:id="@+id/textview_error"
+ android:layout_gravity="center_vertical"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:selectAllOnFocus="true"/>
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_gravity="right"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:orientation="horizontal">
+
+ <Button
+ android:id="@+id/button_dismiss"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:text="@string/button_dismiss"
+ style="?android:attr/buttonBarPositiveButtonStyle"/>
+
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/packages/DocumentsUI/res/layout/item_message_grid.xml b/packages/DocumentsUI/res/layout/item_message_grid.xml
deleted file mode 100644
index 45d61a506bb5..000000000000
--- a/packages/DocumentsUI/res/layout/item_message_grid.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<com.android.documentsui.GridItem xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="@dimen/grid_height"
- android:paddingStart="?android:attr/listPreferredItemPaddingStart"
- android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
- android:paddingTop="8dp"
- android:paddingBottom="8dp">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- android:gravity="center">
-
- <ImageView
- android:id="@android:id/icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:contentDescription="@null" />
-
- <TextView
- android:id="@android:id/title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:maxLines="4"
- android:ellipsize="end"
- android:paddingTop="8dp"
- android:textAlignment="viewStart"
- android:textAppearance="@android:style/TextAppearance.Material.Body1"
- android:textColor="?android:attr/textColorPrimary" />
-
- </LinearLayout>
-
-</com.android.documentsui.GridItem>
diff --git a/packages/DocumentsUI/res/layout/item_message_list.xml b/packages/DocumentsUI/res/layout/item_message_list.xml
deleted file mode 100644
index 44c8baf8cb68..000000000000
--- a/packages/DocumentsUI/res/layout/item_message_list.xml
+++ /dev/null
@@ -1,54 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:minHeight="@dimen/list_item_height"
- android:paddingStart="@dimen/list_item_padding"
- android:paddingEnd="@dimen/list_item_padding"
- android:paddingTop="8dp"
- android:paddingBottom="8dp"
- android:gravity="center_vertical"
- android:orientation="horizontal"
- android:baselineAligned="false">
-
- <FrameLayout
- android:layout_width="@dimen/icon_size"
- android:layout_height="@dimen/icon_size"
- android:layout_marginEnd="16dp">
-
- <ImageView
- android:id="@android:id/icon"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:scaleType="centerInside"
- android:contentDescription="@null" />
-
- </FrameLayout>
-
- <TextView
- android:id="@android:id/title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:maxLines="2"
- android:ellipsize="end"
- android:textAlignment="viewStart"
- android:textAppearance="@android:style/TextAppearance.Material.Body1"
- android:textColor="?android:attr/textColorPrimary" />
-
-</LinearLayout>
diff --git a/packages/DocumentsUI/res/menu/activity.xml b/packages/DocumentsUI/res/menu/activity.xml
index 7df152fb9775..673a254f63f5 100644
--- a/packages/DocumentsUI/res/menu/activity.xml
+++ b/packages/DocumentsUI/res/menu/activity.xml
@@ -26,6 +26,7 @@
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
@@ -56,11 +57,18 @@
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_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:showAsAction="never"
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/attrs.xml b/packages/DocumentsUI/res/values/attrs.xml
new file mode 100644
index 000000000000..0afc3a2e4d8b
--- /dev/null
+++ b/packages/DocumentsUI/res/values/attrs.xml
@@ -0,0 +1,20 @@
+<?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>
+ <declare-styleable name="DocumentsBaseTheme">
+ <attr name="colorActionMode" format="color"/>
+ </declare-styleable>
+</resources>
diff --git a/packages/DocumentsUI/res/values/colors.xml b/packages/DocumentsUI/res/values/colors.xml
index 6002dde5040a..cb6957dd3463 100644
--- a/packages/DocumentsUI/res/values/colors.xml
+++ b/packages/DocumentsUI/res/values/colors.xml
@@ -19,18 +19,20 @@
<color name="material_grey_300">#ffeeeeee</color>
<color name="material_grey_600">#ff757575</color>
<color name="material_grey_800">#ff424242</color>
- <color name="material_blue_700">#ff1976d2</color>
- <color name="material_blue_500">#ff2196f3</color>
<color name="primary_dark">@*android:color/material_blue_grey_900</color>
<color name="primary">@*android:color/material_blue_grey_800</color>
<color name="accent">@*android:color/material_deep_teal_500</color>
+ <color name="platform_blue_100">#ffd0d9ff</color>
+ <color name="platform_blue_500">#ff5677fc</color>
+ <color name="platform_blue_700">#ff455ede</color>
+ <color name="platform_blue_a100">#ffa6baff</color>
+ <color name="platform_blue_a200">#ffff5177</color>
+
<color name="directory_background">@color/material_grey_300</color>
<color name="item_doc_grid_background">#FFFFFFFF</color>
<color name="item_doc_grid_protect_background">#88000000</color>
- <color name="status_bar_background">@color/material_blue_700</color>
- <color name="action_mode_status_bar_background">@color/material_grey_800</color>
<color name="band_select_background">#88ffffff</color>
<color name="band_select_border">#44000000</color>
</resources>
diff --git a/packages/DocumentsUI/res/values/strings.xml b/packages/DocumentsUI/res/values/strings.xml
index 4b44d7c7dc16..a4acb604c1ef 100644
--- a/packages/DocumentsUI/res/values/strings.xml
+++ b/packages/DocumentsUI/res/values/strings.xml
@@ -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] -->
@@ -79,7 +81,10 @@
<string name="button_copy">Copy</string>
<!-- Button label that moves files to the current directory [CHAR LIMIT=24] -->
<string name="button_move">Move</string>
-
+ <!-- Button label that hides the error bar [CHAR LIMIT=24] -->
+ <string name="button_dismiss">Dismiss</string>
+ <string name="button_retry">Try Again</string>
+
<!-- Mode that sorts documents by their display name alphabetically [CHAR LIMIT=24] -->
<string name="sort_name">By name</string>
<!-- Mode that sorts documents by their last modified time in descending order; most recent first [CHAR LIMIT=24] -->
diff --git a/packages/DocumentsUI/res/values/styles.xml b/packages/DocumentsUI/res/values/styles.xml
index e67f956112ce..c13f144d0717 100644
--- a/packages/DocumentsUI/res/values/styles.xml
+++ b/packages/DocumentsUI/res/values/styles.xml
@@ -28,6 +28,7 @@
<item name="android:colorPrimaryDark">@color/primary_dark</item>
<item name="android:colorPrimary">@color/primary</item>
<item name="android:colorAccent">@color/accent</item>
+ <item name="colorActionMode">@color/material_grey_800</item>
<item name="android:listDivider">@*android:drawable/list_divider_material</item>
@@ -43,6 +44,7 @@
<item name="actionBarWidgetTheme">@null</item>
<item name="actionBarTheme">@style/ActionBarTheme</item>
<item name="actionBarPopupTheme">@style/ActionBarPopupTheme</item>
+ <item name="colorActionMode">@color/material_grey_800</item>
<item name="android:listDivider">@*android:drawable/list_divider_material</item>
@@ -68,16 +70,27 @@
</style>
<style name="AlertDialogTheme" parent="@android:style/Theme.Material.Light.Dialog.Alert">
- <item name="android:colorAccent">@color/material_blue_700</item>
+ <item name="android:colorAccent">@color/platform_blue_700</item>
</style>
<style name="FilesTheme" parent="@style/DocumentsBaseTheme.FullScreen">
- <item name="android:colorPrimaryDark">@color/material_blue_700</item>
- <item name="android:colorPrimary">@color/material_blue_500</item>
- <item name="android:colorAccent">@color/material_blue_700</item>
- <item name="android:actionModeStyle">@style/ActionModeStyle</item>
-
+ <item name="android:colorPrimaryDark">@color/platform_blue_700</item>
+ <item name="android:colorPrimary">@color/platform_blue_500</item>
+ <item name="android:colorAccent">@color/platform_blue_700</item>
+ <item name="colorControlActivated">@color/platform_blue_a100</item>
+ <item name="android:actionModeStyle">@style/FilesActionModeStyle</item>
+ <item name="colorActionMode">@color/platform_blue_700</item>
<item name="android:alertDialogTheme">@style/AlertDialogTheme</item>
</style>
+ <style name="FilesActionModeStyle" parent="@android:style/Widget.Material.Light.ActionMode">
+ <item name="android:background">@color/platform_blue_100</item>
+ </style>
+
+ <style name="TrimmedHorizontalProgressBar" parent="android:Widget.Material.ProgressBar.Horizontal">
+ <item name="android:indeterminateDrawable">@drawable/progress_indeterminate_horizontal_material_trimmed</item>
+ <item name="android:minHeight">3dp</item>
+ <item name="android:maxHeight">3dp</item>
+ </style>
+
</resources>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
index 1e7a42fa7732..a6a45e59f469 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
@@ -16,13 +16,6 @@
package com.android.documentsui;
-import static com.android.documentsui.BaseActivity.State.ACTION_BROWSE;
-import static com.android.documentsui.BaseActivity.State.ACTION_CREATE;
-import static com.android.documentsui.BaseActivity.State.ACTION_GET_CONTENT;
-import static com.android.documentsui.BaseActivity.State.ACTION_MANAGE;
-import static com.android.documentsui.BaseActivity.State.ACTION_OPEN;
-import static com.android.documentsui.BaseActivity.State.ACTION_OPEN_COPY_DESTINATION;
-import static com.android.documentsui.BaseActivity.State.ACTION_OPEN_TREE;
import static com.android.documentsui.DirectoryFragment.ANIM_DOWN;
import static com.android.documentsui.DirectoryFragment.ANIM_NONE;
import static com.android.documentsui.DirectoryFragment.ANIM_SIDE;
@@ -40,14 +33,11 @@ import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Root;
import android.support.annotation.LayoutRes;
import android.support.annotation.Nullable;
import android.util.Log;
-import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
@@ -74,7 +64,6 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.HashMap;
import java.util.List;
import java.util.concurrent.Executor;
@@ -86,10 +75,12 @@ 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);
public abstract void onDocumentsPicked(List<DocumentInfo> docs);
@@ -109,6 +100,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();
@@ -116,6 +108,7 @@ abstract class BaseActivity extends Activity {
setContentView(mLayoutId);
mRoots = DocumentsApplication.getRootsCache(this);
+ mDirectoryContainer = (DirectoryContainerView) findViewById(R.id.container_directory);
mSearchManager = new SearchManager();
// Base classes must update result in their onCreate.
@@ -123,22 +116,6 @@ abstract class BaseActivity extends Activity {
}
@Override
- public void onResume() {
- super.onResume();
-
- final State state = getDisplayState();
- final RootInfo root = getCurrentRoot();
-
- // If we're browsing a specific root, and that root went away, then we
- // have no reason to hang around
- if (state.action == State.ACTION_BROWSE && root != null) {
- if (mRoots.getRootBlocking(root.authority, root.rootId) == null) {
- finish();
- }
- }
- }
-
- @Override
public boolean onCreateOptionsMenu(Menu menu) {
boolean showMenu = super.onCreateOptionsMenu(menu);
@@ -176,8 +153,10 @@ abstract class BaseActivity extends Activity {
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;
@@ -187,13 +166,17 @@ abstract class BaseActivity extends Activity {
State state = new State();
final Intent intent = getIntent();
- final String action = intent.getAction();
state.localOnly = intent.getBooleanExtra(Intent.EXTRA_LOCAL_ONLY, false);
+
+ state.forceSize = intent.getBooleanExtra(DocumentsContract.EXTRA_SHOW_FILESIZE, false);
+ state.showSize = state.forceSize || LocalPreferences.getDisplayFileSize(this);
+
state.forceAdvanced = intent.getBooleanExtra(DocumentsContract.EXTRA_SHOW_ADVANCED, false);
- state.showAdvanced = state.forceAdvanced ||
- LocalPreferences.getDisplayAdvancedDevices(this);
+ state.showAdvanced = state.forceAdvanced
+ || LocalPreferences.getDisplayAdvancedDevices(this);
+ state.initAcceptMimes(intent);
state.excludedAuthorities = getExcludedAuthorities();
return state;
@@ -217,7 +200,7 @@ abstract class BaseActivity extends Activity {
if (mRoots.isRecentsRoot(root)) {
onCurrentDirectoryChanged(ANIM_SIDE);
} else {
- new PickRootTask(root).executeOnExecutor(getCurrentExecutor());
+ new PickRootTask(root).executeOnExecutor(getExecutorForCurrentDirectory());
}
}
@@ -227,6 +210,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);
@@ -316,6 +300,7 @@ abstract class BaseActivity extends Activity {
* @param anim
*/
final void onCurrentDirectoryChanged(int anim) {
+ mDirectoryContainer.setDrawDisappearingFirst(anim == ANIM_DOWN);
onDirectoryChanged(anim);
final RootsFragment roots = RootsFragment.get(getFragmentManager());
@@ -381,118 +366,6 @@ abstract class BaseActivity extends Activity {
public static String EXTRA_DIRECTORY_COPY = "com.android.documentsui.DIRECTORY_COPY";
}
- public static class State implements android.os.Parcelable {
- public int action;
- public String[] acceptMimes;
-
- /** Explicit user choice */
- public int userMode = MODE_UNKNOWN;
- /** Derived after loader */
- public int derivedMode = MODE_LIST;
-
- /** Explicit user choice */
- public int userSortOrder = SORT_ORDER_UNKNOWN;
- /** Derived after loader */
- public int derivedSortOrder = SORT_ORDER_DISPLAY_NAME;
-
- public boolean allowMultiple;
- public boolean showSize;
- 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;
-
- /** Current user navigation stack; empty implies recents. */
- public DocumentStack stack = new DocumentStack();
- /** Currently active search, overriding any stack. */
- public String currentSearch;
-
- /** Instance state for every shown directory */
- public HashMap<String, SparseArray<Parcelable>> dirState = new HashMap<>();
-
- /** Currently copying file */
- public List<DocumentInfo> selectedDocumentsForCopy = new ArrayList<DocumentInfo>();
-
- /** Name of the package that started DocsUI */
- public List<String> excludedAuthorities = new ArrayList<>();
-
- public static final int ACTION_OPEN = 1;
- public static final int ACTION_CREATE = 2;
- public static final int ACTION_GET_CONTENT = 3;
- public static final int ACTION_OPEN_TREE = 4;
- public static final int ACTION_MANAGE = 5;
- public static final int ACTION_BROWSE = 6;
- public static final int ACTION_BROWSE_ALL = 7;
- public static final int ACTION_OPEN_COPY_DESTINATION = 8;
-
- public static final int MODE_UNKNOWN = 0;
- public static final int MODE_LIST = 1;
- public static final int MODE_GRID = 2;
-
- public static final int SORT_ORDER_UNKNOWN = 0;
- public static final int SORT_ORDER_DISPLAY_NAME = 1;
- public static final int SORT_ORDER_LAST_MODIFIED = 2;
- public static final int SORT_ORDER_SIZE = 3;
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeInt(action);
- out.writeInt(userMode);
- out.writeStringArray(acceptMimes);
- out.writeInt(userSortOrder);
- out.writeInt(allowMultiple ? 1 : 0);
- out.writeInt(showSize ? 1 : 0);
- out.writeInt(localOnly ? 1 : 0);
- out.writeInt(forceAdvanced ? 1 : 0);
- out.writeInt(showAdvanced ? 1 : 0);
- out.writeInt(stackTouched ? 1 : 0);
- out.writeInt(restored ? 1 : 0);
- DurableUtils.writeToParcel(out, stack);
- out.writeString(currentSearch);
- out.writeMap(dirState);
- out.writeList(selectedDocumentsForCopy);
- out.writeList(excludedAuthorities);
- }
-
- public static final Creator<State> CREATOR = new Creator<State>() {
- @Override
- public State createFromParcel(Parcel in) {
- final State state = new State();
- state.action = in.readInt();
- state.userMode = in.readInt();
- state.acceptMimes = in.readStringArray();
- state.userSortOrder = in.readInt();
- state.allowMultiple = in.readInt() != 0;
- state.showSize = in.readInt() != 0;
- state.localOnly = in.readInt() != 0;
- state.forceAdvanced = in.readInt() != 0;
- state.showAdvanced = in.readInt() != 0;
- state.stackTouched = in.readInt() != 0;
- state.restored = in.readInt() != 0;
- DurableUtils.readFromParcel(in, state.stack);
- state.currentSearch = in.readString();
- in.readMap(state.dirState, null);
- in.readList(state.selectedDocumentsForCopy, null);
- in.readList(state.excludedAuthorities, null);
- return state;
- }
-
- @Override
- public State[] newArray(int size) {
- return new State[size];
- }
- };
- }
-
void setDisplayAdvancedDevices(boolean display) {
State state = getDisplayState();
LocalPreferences.setDisplayAdvancedDevices(this, display);
@@ -559,7 +432,7 @@ abstract class BaseActivity extends Activity {
return getDisplayState().stack.peek();
}
- public Executor getCurrentExecutor() {
+ public Executor getExecutorForCurrentDirectory() {
final DocumentInfo cwd = getCurrentDirectory();
if (cwd != null && cwd.authority != null) {
return ProviderExecutor.forAuthority(cwd.authority);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java b/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
index f8ec8f114313..f1492dc7b185 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
@@ -16,6 +16,7 @@
package com.android.documentsui;
+import static com.android.documentsui.Shared.DEBUG;
import static com.android.documentsui.model.DocumentInfo.getCursorLong;
import static com.android.documentsui.model.DocumentInfo.getCursorString;
@@ -56,7 +57,6 @@ import java.util.Objects;
public class CopyService extends IntentService {
public static final String TAG = "CopyService";
- public static final boolean DEBUG = false;
private static final String EXTRA_CANCEL = "com.android.documentsui.CANCEL";
public static final String EXTRA_SRC_LIST = "com.android.documentsui.SRC_LIST";
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
index cfd4ecb96b59..5eacf2132a3c 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -16,15 +16,15 @@
package com.android.documentsui;
-import static com.android.documentsui.BaseActivity.State.ACTION_BROWSE;
-import static com.android.documentsui.BaseActivity.State.ACTION_BROWSE_ALL;
-import static com.android.documentsui.BaseActivity.State.ACTION_CREATE;
-import static com.android.documentsui.BaseActivity.State.ACTION_MANAGE;
-import static com.android.documentsui.BaseActivity.State.MODE_GRID;
-import static com.android.documentsui.BaseActivity.State.MODE_LIST;
-import static com.android.documentsui.BaseActivity.State.MODE_UNKNOWN;
-import static com.android.documentsui.BaseActivity.State.SORT_ORDER_UNKNOWN;
+import static com.android.documentsui.Shared.DEBUG;
import static com.android.documentsui.Shared.TAG;
+import static com.android.documentsui.State.ACTION_BROWSE;
+import static com.android.documentsui.State.ACTION_CREATE;
+import static com.android.documentsui.State.ACTION_MANAGE;
+import static com.android.documentsui.State.MODE_GRID;
+import static com.android.documentsui.State.MODE_LIST;
+import static com.android.documentsui.State.MODE_UNKNOWN;
+import static com.android.documentsui.State.SORT_ORDER_UNKNOWN;
import static com.android.documentsui.model.DocumentInfo.getCursorInt;
import static com.android.documentsui.model.DocumentInfo.getCursorLong;
import static com.android.documentsui.model.DocumentInfo.getCursorString;
@@ -94,14 +94,13 @@ import android.widget.TextView;
import android.widget.Toast;
import com.android.documentsui.BaseActivity.DocumentContext;
-import com.android.documentsui.BaseActivity.State;
import com.android.documentsui.MultiSelectManager.Selection;
import com.android.documentsui.ProviderExecutor.Preemptable;
import com.android.documentsui.RecentsProvider.StateColumns;
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.DocumentStack;
import com.android.documentsui.model.RootInfo;
-import com.android.internal.util.Preconditions;
+
import com.google.common.collect.Lists;
import java.util.ArrayList;
@@ -125,7 +124,6 @@ public class DirectoryFragment extends Fragment {
public static final int REQUEST_COPY_DESTINATION = 1;
private static final int LOADER_ID = 42;
- private static final boolean DEBUG = false;
private static final boolean DEBUG_ENABLE_DND = false;
private static final String EXTRA_TYPE = "type";
@@ -135,6 +133,7 @@ public class DirectoryFragment extends Fragment {
private static final String EXTRA_IGNORE_STATE = "ignoreState";
private Model mModel;
+ private Model.UpdateListener mModelUpdateListener = new ModelUpdateListener();
private final Handler mHandler = new Handler(Looper.getMainLooper());
@@ -159,6 +158,9 @@ public class DirectoryFragment extends Fragment {
private GridLayoutManager mGridLayout;
private int mColumnCount = 1; // This will get updated when layout changes.
+ private MessageBar mMessageBar;
+ private View mProgressBar;
+
public static void showNormal(FragmentManager fm, RootInfo root, DocumentInfo doc, int anim) {
show(fm, TYPE_NORMAL, root, doc, null, anim);
}
@@ -220,6 +222,9 @@ public class DirectoryFragment extends Fragment {
final Resources res = context.getResources();
final View view = inflater.inflate(R.layout.fragment_directory, container, false);
+ mMessageBar = MessageBar.create(getChildFragmentManager());
+ mProgressBar = view.findViewById(R.id.progressbar);
+
mEmptyView = view.findViewById(android.R.id.empty);
mRecView = (RecyclerView) view.findViewById(R.id.recyclerView);
@@ -307,9 +312,8 @@ public class DirectoryFragment extends Fragment {
: MultiSelectManager.MODE_SINGLE);
selMgr.addCallback(new SelectionModeListener());
- mModel = new Model(context, selMgr);
- mModel.setSelectionManager(selMgr);
- mModel.addUpdateListener(mAdapter);
+ mModel = new Model(context, selMgr, mAdapter);
+ mModel.addUpdateListener(mModelUpdateListener);
mType = getArguments().getInt(EXTRA_TYPE);
mStateKey = buildStateKey(root, doc);
@@ -362,21 +366,6 @@ public class DirectoryFragment extends Fragment {
@Override
public void onLoadFinished(Loader<DirectoryResult> loader, DirectoryResult result) {
- if (result == null || result.exception != null) {
- // onBackPressed does a fragment transaction, which can't be done inside
- // onLoadFinished
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- final Activity activity = getActivity();
- if (activity != null) {
- activity.onBackPressed();
- }
- }
- });
- return;
- }
-
if (!isAdded()) return;
mModel.update(result);
@@ -611,7 +600,7 @@ public class DirectoryFragment extends Fragment {
@Override
public boolean onBeforeItemStateChange(int position, boolean selected) {
- // Directories and footer items cannot be checked
+ // Directories cannot be checked
if (selected) {
final Cursor cursor = mModel.getItem(position);
checkNotNull(cursor, "Cursor cannot be null.");
@@ -624,7 +613,6 @@ public class DirectoryFragment extends Fragment {
@Override
public void onItemStateChanged(int position, boolean selected) {
-
final Cursor cursor = mModel.getItem(position);
checkNotNull(cursor, "Cursor cannot be null.");
@@ -637,27 +625,25 @@ public class DirectoryFragment extends Fragment {
@Override
public void onSelectionChanged() {
mModel.getSelection(mSelected);
+ TypedValue color = new TypedValue();
if (mSelected.size() > 0) {
if (DEBUG) Log.d(TAG, "Maybe starting action mode.");
if (mActionMode == null) {
if (DEBUG) Log.d(TAG, "Yeah. Starting action mode.");
mActionMode = getActivity().startActionMode(this);
- getActivity().getWindow().setStatusBarColor(
- getResources().getColor(R.color.action_mode_status_bar_background));
}
+ getActivity().getTheme().resolveAttribute(
+ R.attr.colorActionMode, color, true);
updateActionMenu();
} else {
if (DEBUG) Log.d(TAG, "Finishing action mode.");
if (mActionMode != null) {
mActionMode.finish();
}
- // Obtain the original status bar color from the theme, and restore it.
- TypedValue color = new TypedValue();
getActivity().getTheme().resolveAttribute(
android.R.attr.colorPrimaryDark, color, true);
- getActivity().getWindow().setStatusBarColor(color.data);
-
}
+ getActivity().getWindow().setStatusBarColor(color.data);
if (mActionMode != null) {
mActionMode.setTitle(TextUtils.formatSelectedCount(mSelected.size()));
@@ -712,8 +698,9 @@ public class DirectoryFragment extends Fragment {
return true;
} else if (id == R.id.menu_delete) {
- deleteDocuments(selection);
+ // Exit selection mode first, so we avoid deselecting deleted documents.
mode.finish();
+ deleteDocuments(selection);
return true;
} else if (id == R.id.menu_copy_to) {
@@ -722,8 +709,9 @@ public class DirectoryFragment extends Fragment {
return true;
} else if (id == R.id.menu_move_to) {
- transferDocuments(selection, CopyService.TRANSFER_MODE_MOVE);
+ // Exit selection mode first, so we avoid deselecting deleted documents.
mode.finish();
+ transferDocuments(selection, CopyService.TRANSFER_MODE_MOVE);
return true;
} else if (id == R.id.menu_copy_to_clipboard) {
@@ -882,79 +870,6 @@ public class DirectoryFragment extends Fragment {
return ((BaseActivity) fragment.getActivity()).getDisplayState();
}
- private static abstract class Footer {
- private final int mItemViewType;
-
- public Footer(int itemViewType) {
- mItemViewType = itemViewType;
- }
-
- public abstract View getView(View convertView, ViewGroup parent);
-
- public int getItemViewType() {
- return mItemViewType;
- }
- }
-
- private class LoadingFooter extends Footer {
- public LoadingFooter() {
- super(1);
- }
-
- @Override
- public View getView(View convertView, ViewGroup parent) {
- final Context context = parent.getContext();
- final State state = getDisplayState(DirectoryFragment.this);
-
- if (convertView == null) {
- final LayoutInflater inflater = LayoutInflater.from(context);
- if (state.derivedMode == MODE_LIST) {
- convertView = inflater.inflate(R.layout.item_loading_list, parent, false);
- } else if (state.derivedMode == MODE_GRID) {
- convertView = inflater.inflate(R.layout.item_loading_grid, parent, false);
- } else {
- throw new IllegalStateException();
- }
- }
-
- return convertView;
- }
- }
-
- private class MessageFooter extends Footer {
- private final int mIcon;
- private final String mMessage;
-
- public MessageFooter(int itemViewType, int icon, String message) {
- super(itemViewType);
- mIcon = icon;
- mMessage = message;
- }
-
- @Override
- public View getView(View convertView, ViewGroup parent) {
- final Context context = parent.getContext();
- final State state = getDisplayState(DirectoryFragment.this);
-
- if (convertView == null) {
- final LayoutInflater inflater = LayoutInflater.from(context);
- if (state.derivedMode == MODE_LIST) {
- convertView = inflater.inflate(R.layout.item_message_list, parent, false);
- } else if (state.derivedMode == MODE_GRID) {
- convertView = inflater.inflate(R.layout.item_message_grid, parent, false);
- } else {
- throw new IllegalStateException();
- }
- }
-
- final ImageView icon = (ImageView) convertView.findViewById(android.R.id.icon);
- final TextView title = (TextView) convertView.findViewById(android.R.id.title);
- icon.setImageResource(mIcon);
- title.setText(mMessage);
- return convertView;
- }
- }
-
// Provide a reference to the views for each data item
// Complex data items may need more than one view per item, and
// you provide access to all the views for a data item in a view holder
@@ -968,46 +883,39 @@ public class DirectoryFragment extends Fragment {
}
}
- private final class DocumentsAdapter extends RecyclerView.Adapter<DocumentHolder>
- implements Model.UpdateListener {
+ void showEmptyView() {
+ mEmptyView.setVisibility(View.VISIBLE);
+ mRecView.setVisibility(View.GONE);
+ TextView msg = (TextView) mEmptyView.findViewById(R.id.message);
+ msg.setText(R.string.empty);
+ // No retry button for the empty view.
+ mEmptyView.findViewById(R.id.button_retry).setVisibility(View.GONE);
+ }
+
+ void showErrorView() {
+ mEmptyView.setVisibility(View.VISIBLE);
+ mRecView.setVisibility(View.GONE);
+ TextView msg = (TextView) mEmptyView.findViewById(R.id.message);
+ msg.setText(R.string.query_error);
+ // TODO: Enable this once the retry button does something.
+ mEmptyView.findViewById(R.id.button_retry).setVisibility(View.GONE);
+ }
+
+ void showRecyclerView() {
+ mEmptyView.setVisibility(View.GONE);
+ mRecView.setVisibility(View.VISIBLE);
+ }
+
+ private final class DocumentsAdapter extends RecyclerView.Adapter<DocumentHolder> {
private final Context mContext;
private final LayoutInflater mInflater;
- // TODO: Bring back support for footers.
- private final List<Footer> mFooters = new ArrayList<>();
public DocumentsAdapter(Context context) {
mContext = context;
mInflater = LayoutInflater.from(context);
}
- public void onModelUpdate(Model model) {
- mFooters.clear();
- if (model.info != null) {
- mFooters.add(new MessageFooter(2, R.drawable.ic_dialog_info, model.info));
- }
- if (model.error != null) {
- mFooters.add(new MessageFooter(3, R.drawable.ic_dialog_alert, model.error));
- }
- if (model.isLoading()) {
- mFooters.add(new LoadingFooter());
- }
-
- if (model.isEmpty()) {
- mEmptyView.setVisibility(View.VISIBLE);
- } else {
- mEmptyView.setVisibility(View.GONE);
- }
-
- notifyDataSetChanged();
- }
-
- public void onModelUpdateFailed(Exception e) {
- String error = getString(R.string.query_error);
- mFooters.add(new MessageFooter(3, R.drawable.ic_dialog_alert, error));
- notifyDataSetChanged();
- }
-
@Override
public DocumentHolder onCreateViewHolder(ViewGroup parent, int viewType) {
final State state = getDisplayState(DirectoryFragment.this);
@@ -1224,19 +1132,8 @@ public class DirectoryFragment extends Fragment {
@Override
public int getItemCount() {
return mModel.getItemCount();
- // return mCursorCount + mFooters.size();
}
- @Override
- public int getItemViewType(int position) {
- final int itemCount = mModel.getItemCount();
- if (position < itemCount) {
- return 0;
- } else {
- position -= itemCount;
- return mFooters.get(position).getItemViewType();
- }
- }
}
private static String formatTime(Context context, long when) {
@@ -1521,7 +1418,8 @@ public class DirectoryFragment extends Fragment {
getClipDataFromDocuments(docs),
new DrawableShadowBuilder(getDragShadowIcon(docs)),
null,
- View.DRAG_FLAG_GLOBAL
+ View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_GLOBAL_URI_READ |
+ View.DRAG_FLAG_GLOBAL_URI_WRITE
);
return true;
}
@@ -1662,9 +1560,9 @@ public class DirectoryFragment extends Fragment {
}
private FragmentTuner pickFragmentTuner(final State state) {
- return state.action == ACTION_BROWSE_ALL
+ return state.action == ACTION_BROWSE
? new FilesTuner()
- : new DefaultTuner(state);
+ : new DefaultTuner(state.action);
}
/**
@@ -1701,15 +1599,14 @@ public class DirectoryFragment extends Fragment {
*/
private static final class DefaultTuner implements FragmentTuner {
- private final State mState;
+ private final boolean mManaging;
- public DefaultTuner(State state) {
- mState = state;
+ public DefaultTuner(int action) {
+ mManaging = (action == ACTION_MANAGE);
}
@Override
public void updateActionMenu(Menu menu, int dirType, boolean canDelete) {
- Preconditions.checkState(mState.action != ACTION_BROWSE_ALL);
final MenuItem open = menu.findItem(R.id.menu_open);
final MenuItem share = menu.findItem(R.id.menu_share);
@@ -1718,14 +1615,11 @@ public class DirectoryFragment extends Fragment {
final MenuItem moveTo = menu.findItem(R.id.menu_move_to);
final MenuItem copyToClipboard = menu.findItem(R.id.menu_copy_to_clipboard);
- final boolean manageOrBrowse = (mState.action == ACTION_MANAGE
- || mState.action == ACTION_BROWSE);
-
- open.setVisible(!manageOrBrowse);
- share.setVisible(manageOrBrowse);
- delete.setVisible(manageOrBrowse && canDelete);
+ open.setVisible(!mManaging);
+ share.setVisible(mManaging);
+ delete.setVisible(mManaging && canDelete);
// Disable copying from the Recents view.
- copyTo.setVisible(manageOrBrowse && dirType != TYPE_RECENT_OPEN);
+ copyTo.setVisible(mManaging && dirType != TYPE_RECENT_OPEN);
moveTo.setVisible(SystemProperties.getBoolean("debug.documentsui.enable_move", false));
// Only shown in files mode.
@@ -1742,6 +1636,7 @@ public class DirectoryFragment extends Fragment {
private static final class FilesTuner implements FragmentTuner {
@Override
public void updateActionMenu(Menu menu, int dirType, boolean canDelete) {
+
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);
@@ -1761,6 +1656,7 @@ public class DirectoryFragment extends Fragment {
@VisibleForTesting
public static final class Model implements DocumentContext {
private MultiSelectManager mSelectionManager;
+ private RecyclerView.Adapter<?> mViewAdapter;
private Context mContext;
private int mCursorCount;
private boolean mIsLoading;
@@ -1770,17 +1666,11 @@ public class DirectoryFragment extends Fragment {
@Nullable private String info;
@Nullable private String error;
- Model(Context context, MultiSelectManager selectionManager) {
+ Model(Context context, MultiSelectManager selectionManager,
+ RecyclerView.Adapter<?> viewAdapter) {
mContext = context;
mSelectionManager = selectionManager;
- }
-
- /**
- * Sets the selection manager used by the model.
- * TODO: the model should instantiate the selection manager. See onActivityCreated.
- */
- void setSelectionManager(MultiSelectManager mgr) {
- mSelectionManager = mgr;
+ mViewAdapter = viewAdapter;
}
/**
@@ -1945,7 +1835,7 @@ public class DirectoryFragment extends Fragment {
int position = selected.get(i);
if (DEBUG) Log.d(TAG, "Marked position " + position + " for deletion");
mMarkedForDeletion.append(position, true);
- mUpdateListener.notifyItemRemoved(position);
+ mViewAdapter.notifyItemRemoved(position);
}
}
@@ -1960,7 +1850,7 @@ public class DirectoryFragment extends Fragment {
for (int i = 0; i < size; ++i) {
final int position = mMarkedForDeletion.keyAt(i);
mMarkedForDeletion.put(position, false);
- mUpdateListener.notifyItemInserted(position);
+ mViewAdapter.notifyItemInserted(position);
}
// Then, clear the deletion list.
@@ -2043,26 +1933,41 @@ public class DirectoryFragment extends Fragment {
mUpdateListener = listener;
}
- interface UpdateListener {
+ static class UpdateListener {
/**
* Called when a successful update has occurred.
*/
- void onModelUpdate(Model model);
+ void onModelUpdate(Model model) {}
/**
* Called when an update has been attempted but failed.
*/
- void onModelUpdateFailed(Exception e);
+ void onModelUpdateFailed(Exception e) {}
+ }
+ }
- /**
- * Called when an item has been removed from the model.
- */
- void notifyItemRemoved(int position);
+ private class ModelUpdateListener extends Model.UpdateListener {
+ @Override
+ public void onModelUpdate(Model model) {
+ if (model.info != null || model.error != null) {
+ mMessageBar.setInfo(model.info);
+ mMessageBar.setError(model.error);
+ mMessageBar.show();
+ }
- /**
- * Called when an item has been added to the model.
- */
- void notifyItemInserted(int position);
+ mProgressBar.setVisibility(model.isLoading() ? View.VISIBLE : View.GONE);
+
+ if (model.isEmpty()) {
+ showEmptyView();
+ } else {
+ showRecyclerView();
+ mAdapter.notifyDataSetChanged();
+ }
+ }
+
+ @Override
+ public void onModelUpdateFailed(Exception e) {
+ showErrorView();
}
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
index 0edb2413b0ca..bb82b386aa12 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
@@ -16,12 +16,12 @@
package com.android.documentsui;
-import static com.android.documentsui.BaseActivity.State.MODE_UNKNOWN;
-import static com.android.documentsui.BaseActivity.State.SORT_ORDER_DISPLAY_NAME;
-import static com.android.documentsui.BaseActivity.State.SORT_ORDER_LAST_MODIFIED;
-import static com.android.documentsui.BaseActivity.State.SORT_ORDER_SIZE;
-import static com.android.documentsui.BaseActivity.State.SORT_ORDER_UNKNOWN;
import static com.android.documentsui.Shared.TAG;
+import static com.android.documentsui.State.MODE_UNKNOWN;
+import static com.android.documentsui.State.SORT_ORDER_DISPLAY_NAME;
+import static com.android.documentsui.State.SORT_ORDER_LAST_MODIFIED;
+import static com.android.documentsui.State.SORT_ORDER_SIZE;
+import static com.android.documentsui.State.SORT_ORDER_UNKNOWN;
import static com.android.documentsui.model.DocumentInfo.getCursorInt;
import android.content.AsyncTaskLoader;
@@ -37,7 +37,6 @@ import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
import android.util.Log;
-import com.android.documentsui.BaseActivity.State;
import com.android.documentsui.RecentsProvider.StateColumns;
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.RootInfo;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryView.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryView.java
index 4893652c4849..000b92a0b1a5 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryView.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryView.java
@@ -18,9 +18,9 @@ package com.android.documentsui;
import android.content.Context;
import android.util.AttributeSet;
-import android.widget.FrameLayout;
+import android.widget.LinearLayout;
-public class DirectoryView extends FrameLayout {
+public class DirectoryView extends LinearLayout {
private float mPosition = 0f;
private int mWidth;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index 1de1c6a57028..4658fe366bd8 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -16,19 +16,16 @@
package com.android.documentsui;
-import static com.android.documentsui.BaseActivity.State.ACTION_BROWSE;
-import static com.android.documentsui.BaseActivity.State.ACTION_CREATE;
-import static com.android.documentsui.BaseActivity.State.ACTION_GET_CONTENT;
-import static com.android.documentsui.BaseActivity.State.ACTION_OPEN;
-import static com.android.documentsui.BaseActivity.State.ACTION_OPEN_COPY_DESTINATION;
-import static com.android.documentsui.BaseActivity.State.ACTION_OPEN_TREE;
-import static com.android.documentsui.DirectoryFragment.ANIM_DOWN;
import static com.android.documentsui.DirectoryFragment.ANIM_NONE;
+import static com.android.documentsui.State.ACTION_CREATE;
+import static com.android.documentsui.State.ACTION_GET_CONTENT;
+import static com.android.documentsui.State.ACTION_OPEN;
+import static com.android.documentsui.State.ACTION_OPEN_COPY_DESTINATION;
+import static com.android.documentsui.State.ACTION_OPEN_TREE;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
-import android.content.ActivityNotFoundException;
import android.content.ClipData;
import android.content.ComponentName;
import android.content.ContentProviderClient;
@@ -44,7 +41,6 @@ import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Parcelable;
import android.provider.DocumentsContract;
-import android.provider.DocumentsContract.Root;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
@@ -75,8 +71,6 @@ public class DocumentsActivity extends BaseActivity {
private Toolbar mRootsToolbar;
- private DirectoryContainerView mDirectoryContainer;
-
private ItemSelectedListener mStackListener;
private BaseAdapter mStackAdapter;
@@ -89,7 +83,7 @@ public class DocumentsActivity extends BaseActivity {
super.onCreate(icicle);
final Resources res = getResources();
- mShowAsDialog = res.getBoolean(R.bool.show_as_dialog) && mState.action != ACTION_BROWSE;
+ mShowAsDialog = res.getBoolean(R.bool.show_as_dialog);
if (!mShowAsDialog) {
setTheme(R.style.DocumentsNonDialogTheme);
@@ -114,8 +108,6 @@ public class DocumentsActivity extends BaseActivity {
mDrawer = DrawerController.create(this);
}
- mDirectoryContainer = (DirectoryContainerView) findViewById(R.id.container_directory);
-
mToolbar = (Toolbar) findViewById(R.id.toolbar);
mStackAdapter = new StackAdapter();
@@ -127,14 +119,6 @@ public class DocumentsActivity extends BaseActivity {
setActionBar(mToolbar);
- // Hide roots when we're managing a specific root
- if (mState.action == ACTION_BROWSE) {
- mDrawer.lockClosed();
- if (mShowAsDialog) {
- findViewById(R.id.container_roots).setVisibility(View.GONE);
- }
- }
-
if (mState.action == ACTION_CREATE) {
final String mimeType = getIntent().getType();
final String title = getIntent().getStringExtra(Intent.EXTRA_TITLE);
@@ -160,12 +144,7 @@ public class DocumentsActivity extends BaseActivity {
// In this case, we set the activity title in AsyncTask.onPostExecute(). To prevent
// talkback from reading aloud the default title, we clear it here.
setTitle("");
- if (mState.action == ACTION_BROWSE) {
- final Uri rootUri = getIntent().getData();
- new RestoreRootTask(rootUri).executeOnExecutor(getCurrentExecutor());
- } else {
- new RestoreStackTask().execute();
- }
+ new RestoreStackTask().execute();
} else {
onCurrentDirectoryChanged(ANIM_NONE);
}
@@ -185,8 +164,6 @@ public class DocumentsActivity extends BaseActivity {
state.action = ACTION_GET_CONTENT;
} else if (Intent.ACTION_OPEN_DOCUMENT_TREE.equals(action)) {
state.action = ACTION_OPEN_TREE;
- } else if (DocumentsContract.ACTION_BROWSE_DOCUMENT_ROOT.equals(action)) {
- state.action = ACTION_BROWSE;
} else if (DocumentsIntent.ACTION_OPEN_COPY_DESTINATION.equals(action)) {
state.action = ACTION_OPEN_COPY_DESTINATION;
}
@@ -196,20 +173,6 @@ public class DocumentsActivity extends BaseActivity {
Intent.EXTRA_ALLOW_MULTIPLE, false);
}
- if (state.action == ACTION_BROWSE) {
- state.acceptMimes = new String[] { "*/*" };
- state.allowMultiple = true;
- } else if (intent.hasExtra(Intent.EXTRA_MIME_TYPES)) {
- state.acceptMimes = intent.getStringArrayExtra(Intent.EXTRA_MIME_TYPES);
- } else {
- state.acceptMimes = new String[] { intent.getType() };
- }
-
- if (state.action == ACTION_BROWSE) {
- state.showSize = true;
- } else {
- state.showSize = LocalPreferences.getDisplayFileSize(this);
- }
if (state.action == ACTION_OPEN_COPY_DESTINATION) {
state.directoryCopy = intent.getBooleanExtra(
BaseActivity.DocumentsIntent.EXTRA_DIRECTORY_COPY, false);
@@ -361,11 +324,7 @@ public class DocumentsActivity extends BaseActivity {
final MenuItem fileSize = menu.findItem(R.id.menu_file_size);
final MenuItem settings = menu.findItem(R.id.menu_settings);
- // File size is locked visible for browse because that is the action triggered by Settings,
- // where the user is trying to find large files to clean up.
- // TODO: instead of setting this according to the action, use a local preference, but
- // provide a @hide extra to let callers like Settings force-enable size visibility.
- boolean fileSizeVisible = mState.action != ACTION_BROWSE;
+ boolean fileSizeVisible = mState.showSize && !mState.forceSize;
if (mState.action == ACTION_CREATE
|| mState.action == ACTION_OPEN_TREE
|| mState.action == ACTION_OPEN_COPY_DESTINATION) {
@@ -387,11 +346,9 @@ public class DocumentsActivity extends BaseActivity {
createDir.setVisible(false);
}
- advanced.setVisible(mState.action != ACTION_BROWSE && !mState.forceAdvanced);
+ advanced.setVisible(!mState.forceAdvanced);
fileSize.setVisible(fileSizeVisible);
-
- settings.setVisible(mState.action == ACTION_BROWSE
- && (root.flags & Root.FLAG_HAS_SETTINGS) != 0);
+ settings.setVisible(false);
return true;
}
@@ -407,8 +364,6 @@ public class DocumentsActivity extends BaseActivity {
final RootInfo root = getCurrentRoot();
final DocumentInfo cwd = getCurrentDirectory();
- mDirectoryContainer.setDrawDisappearingFirst(anim == ANIM_DOWN);
-
if (cwd == null) {
// No directory means recents
if (mState.action == ACTION_CREATE ||
@@ -452,11 +407,11 @@ public class DocumentsActivity extends BaseActivity {
}
void onSaveRequested(DocumentInfo replaceTarget) {
- new ExistingFinishTask(replaceTarget.derivedUri).executeOnExecutor(getCurrentExecutor());
+ new ExistingFinishTask(replaceTarget.derivedUri).executeOnExecutor(getExecutorForCurrentDirectory());
}
void onSaveRequested(String mimeType, String displayName) {
- new CreateFinishTask(mimeType, displayName).executeOnExecutor(getCurrentExecutor());
+ new CreateFinishTask(mimeType, displayName).executeOnExecutor(getExecutorForCurrentDirectory());
}
@Override
@@ -472,21 +427,10 @@ public class DocumentsActivity extends BaseActivity {
openDirectory(doc);
} else if (mState.action == ACTION_OPEN || mState.action == ACTION_GET_CONTENT) {
// Explicit file picked, return
- new ExistingFinishTask(doc.derivedUri).executeOnExecutor(getCurrentExecutor());
+ new ExistingFinishTask(doc.derivedUri).executeOnExecutor(getExecutorForCurrentDirectory());
} else if (mState.action == ACTION_CREATE) {
// Replace selected file
SaveFragment.get(fm).setReplaceTarget(doc);
- } else if (mState.action == ACTION_BROWSE) {
- // Go straight to viewing
- final Intent view = new Intent(Intent.ACTION_VIEW);
- view.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
- view.setData(doc.derivedUri);
-
- try {
- startActivity(view);
- } catch (ActivityNotFoundException ex) {
- Toast.makeText(this, R.string.toast_no_application, Toast.LENGTH_SHORT).show();
- }
}
}
@@ -498,7 +442,7 @@ public class DocumentsActivity extends BaseActivity {
for (int i = 0; i < size; i++) {
uris[i] = docs.get(i).derivedUri;
}
- new ExistingFinishTask(uris).executeOnExecutor(getCurrentExecutor());
+ new ExistingFinishTask(uris).executeOnExecutor(getExecutorForCurrentDirectory());
}
}
@@ -513,7 +457,7 @@ public class DocumentsActivity extends BaseActivity {
// Should not be reached.
throw new IllegalStateException("Invalid mState.action.");
}
- new PickFinishTask(result).executeOnExecutor(getCurrentExecutor());
+ new PickFinishTask(result).executeOnExecutor(getExecutorForCurrentDirectory());
}
@Override
diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
index 8f9025a1cdeb..e8d10888af47 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
@@ -16,8 +16,10 @@
package com.android.documentsui;
-import static com.android.documentsui.DirectoryFragment.ANIM_DOWN;
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;
@@ -25,11 +27,9 @@ import android.content.ActivityNotFoundException;
import android.content.ClipData;
import android.content.ContentResolver;
import android.content.ContentValues;
-import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
-import android.provider.DocumentsContract;
import android.support.annotation.Nullable;
import android.util.Log;
import android.view.KeyEvent;
@@ -46,7 +46,6 @@ import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.DocumentStack;
import com.android.documentsui.model.DurableUtils;
import com.android.documentsui.model.RootInfo;
-import com.android.internal.util.Preconditions;
import java.util.ArrayList;
import java.util.Arrays;
@@ -58,11 +57,9 @@ import java.util.List;
public class FilesActivity extends BaseActivity {
public static final String TAG = "FilesActivity";
- static final boolean DEBUG = false;
private Toolbar mToolbar;
private Spinner mToolbarStack;
- private DirectoryContainerView mDirectoryContainer;
private ItemSelectedListener mStackListener;
private BaseAdapter mStackAdapter;
private DocumentClipper mClipper;
@@ -75,10 +72,6 @@ public class FilesActivity extends BaseActivity {
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
- final Context context = this;
-
- mDirectoryContainer = (DirectoryContainerView) findViewById(R.id.container_directory);
-
mToolbar = (Toolbar) findViewById(R.id.toolbar);
mStackAdapter = new StackAdapter();
@@ -90,17 +83,22 @@ public class FilesActivity extends BaseActivity {
mClipper = new DocumentClipper(this);
mDrawer = DrawerController.create(this);
- if (mDrawer.isPresent()) {
- setTheme(R.style.DocumentsNonDialogTheme);
- }
-
RootsFragment.show(getFragmentManager(), null);
if (!mState.restored) {
- new RestoreStackTask().execute();
+ Intent intent = getIntent();
+ Uri rootUri = intent.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 && !LauncherActivity.isLaunchUri(rootUri)) {
+ new RestoreRootTask(rootUri).executeOnExecutor(
+ ProviderExecutor.forAuthority(rootUri.getAuthority()));
+ } else {
+ new RestoreStackTask().execute();
+ }
// 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,
@@ -122,22 +120,16 @@ public class FilesActivity extends BaseActivity {
final Intent intent = getIntent();
- state.action = State.ACTION_BROWSE_ALL;
- state.acceptMimes = new String[] { intent.getType() };
+ state.action = State.ACTION_BROWSE;
state.allowMultiple = true;
- // These options are specific to the DocumentsActivity.
- Preconditions.checkArgument(
- !intent.hasExtra(Intent.EXTRA_LOCAL_ONLY));
- Preconditions.checkArgument(
- !intent.hasExtra(DocumentsContract.EXTRA_SHOW_ADVANCED));
-
- state.showAdvanced = LocalPreferences.getDisplayAdvancedDevices(this);
- state.showSize = LocalPreferences.getDisplayFileSize(this);
+ // Options specific to the DocumentsActivity.
+ checkArgument(!intent.hasExtra(Intent.EXTRA_LOCAL_ONLY));
final DocumentStack stack = intent.getParcelableExtra(CopyService.EXTRA_STACK);
- if (stack != null)
+ if (stack != null) {
state.stack = stack;
+ }
return state;
}
@@ -149,6 +141,21 @@ public class FilesActivity extends BaseActivity {
}
@Override
+ public void onResume() {
+ super.onResume();
+
+ final RootInfo root = getCurrentRoot();
+
+ // If we're browsing a specific root, and that root went away, then we
+ // have no reason to hang around.
+ // TODO: Rather than just disappearing, maybe we should inform
+ // the user what has happened, let them close us. Less surprising.
+ if (mRoots.getRootBlocking(root.authority, root.rootId) == null) {
+ finish();
+ }
+ }
+
+ @Override
public void updateActionBar() {
final RootInfo root = getCurrentRoot();
@@ -204,17 +211,22 @@ public class FilesActivity extends BaseActivity {
menu.findItem(R.id.menu_file_size).setVisible(true);
menu.findItem(R.id.menu_advanced).setVisible(true);
- final MenuItem pasteFromCb = menu.findItem(R.id.menu_paste_from_clipboard);
final MenuItem createDir = menu.findItem(R.id.menu_create_dir);
- final MenuItem settings = menu.findItem(R.id.menu_settings);
+ final MenuItem newWindow = menu.findItem(R.id.menu_new_window);
+ final MenuItem pasteFromCb = menu.findItem(R.id.menu_paste_from_clipboard);
boolean canCreateDir = canCreateDirectory();
createDir.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
createDir.setVisible(canCreateDir);
+ createDir.setEnabled(canCreateDir);
+
+ newWindow.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
+ newWindow.setVisible(mProductivityDevice);
+ newWindow.setEnabled(mProductivityDevice);
- pasteFromCb.setVisible(true);
pasteFromCb.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
+ pasteFromCb.setVisible(true);
pasteFromCb.setEnabled(mClipper.hasItemsToPaste());
return shown;
@@ -222,12 +234,19 @@ public class FilesActivity extends BaseActivity {
@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:
+ startActivity(LauncherActivity.createLaunchIntent(this));
+ 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);
@@ -239,8 +258,6 @@ public class FilesActivity extends BaseActivity {
final RootInfo root = getCurrentRoot();
final DocumentInfo cwd = getCurrentDirectory();
- mDirectoryContainer.setDrawDisappearingFirst(anim == ANIM_DOWN);
-
if (cwd == null) {
DirectoryFragment.showRecentsOpen(fm, anim);
@@ -317,19 +334,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/IconUtils.java b/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
index ec1cb1de5c57..a1213d210b50 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
@@ -222,7 +222,7 @@ public class IconUtils {
return context.getDrawable(R.drawable.ic_doc_album);
}
- if (mode == BaseActivity.State.MODE_GRID) {
+ if (mode == State.MODE_GRID) {
return context.getDrawable(R.drawable.ic_grid_folder);
} else {
return context.getDrawable(R.drawable.ic_doc_folder);
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 740157829d3f..4754899b95cc 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/ManageRootActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/ManageRootActivity.java
@@ -16,9 +16,8 @@
package com.android.documentsui;
-import static com.android.documentsui.BaseActivity.State.ACTION_MANAGE;
-import static com.android.documentsui.DirectoryFragment.ANIM_DOWN;
import static com.android.documentsui.DirectoryFragment.ANIM_NONE;
+import static com.android.documentsui.State.ACTION_MANAGE;
import android.app.Activity;
import android.app.Fragment;
@@ -56,8 +55,6 @@ public class ManageRootActivity extends BaseActivity {
private Toolbar mToolbar;
private Spinner mToolbarStack;
- private DirectoryContainerView mDirectoryContainer;
-
private ItemSelectedListener mStackListener;
private BaseAdapter mStackAdapter;
@@ -73,8 +70,6 @@ public class ManageRootActivity extends BaseActivity {
mDrawer = DrawerController.createDummy();
- mDirectoryContainer = (DirectoryContainerView) findViewById(R.id.container_directory);
-
mToolbar = (Toolbar) findViewById(R.id.toolbar);
mToolbar.setTitleTextAppearance(context,
android.R.style.TextAppearance_DeviceDefault_Widget_ActionBar_Title);
@@ -91,7 +86,7 @@ public class ManageRootActivity extends BaseActivity {
// talkback from reading aloud the default title, we clear it here.
setTitle("");
final Uri rootUri = getIntent().getData();
- new RestoreRootTask(rootUri).executeOnExecutor(getCurrentExecutor());
+ new RestoreRootTask(rootUri).executeOnExecutor(getExecutorForCurrentDirectory());
} else {
onCurrentDirectoryChanged(ANIM_NONE);
}
@@ -157,7 +152,6 @@ public class ManageRootActivity extends BaseActivity {
// If started in manage roots mode, there has to be a cwd (i.e. the root dir of the managed
// root).
Preconditions.checkNotNull(cwd);
- mDirectoryContainer.setDrawDisappearingFirst(anim == ANIM_DOWN);
if (mState.currentSearch != null) {
// Ongoing search
diff --git a/packages/DocumentsUI/src/com/android/documentsui/MessageBar.java b/packages/DocumentsUI/src/com/android/documentsui/MessageBar.java
new file mode 100644
index 000000000000..312d53b9dc1c
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/MessageBar.java
@@ -0,0 +1,129 @@
+/*
+ * 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.annotation.Nullable;
+import android.app.Fragment;
+import android.app.FragmentManager;
+import android.app.FragmentTransaction;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+/**
+ * A message bar displaying some info/error messages and a Dismiss button.
+ */
+public class MessageBar extends Fragment {
+ private View mView;
+ private ViewGroup mContainer;
+
+ /**
+ * Creates an instance of a MessageBar. Note that the new MessagBar is not visible by default,
+ * and has to be shown by calling MessageBar.show.
+ */
+ public static MessageBar create(FragmentManager fm) {
+ final MessageBar fragment = new MessageBar();
+
+ final FragmentTransaction ft = fm.beginTransaction();
+ ft.replace(R.id.container_message_bar, fragment);
+ ft.commitAllowingStateLoss();
+
+ return fragment;
+ }
+
+ /**
+ * Sets the info message. Can be null, in which case no info message will be displayed. The
+ * message bar layout will be adjusted accordingly.
+ */
+ public void setInfo(@Nullable String info) {
+ View infoContainer = mView.findViewById(R.id.container_info);
+ if (info != null) {
+ TextView infoText = (TextView) mView.findViewById(R.id.textview_info);
+ infoText.setText(info);
+ infoContainer.setVisibility(View.VISIBLE);
+ } else {
+ infoContainer.setVisibility(View.GONE);
+ }
+ }
+
+ /**
+ * Sets the error message. Can be null, in which case no error message will be displayed. The
+ * message bar layout will be adjusted accordingly.
+ */
+ public void setError(@Nullable String error) {
+ View errorView = mView.findViewById(R.id.container_error);
+ if (error != null) {
+ TextView errorText = (TextView) mView.findViewById(R.id.textview_error);
+ errorText.setText(error);
+ errorView.setVisibility(View.VISIBLE);
+ } else {
+ errorView.setVisibility(View.GONE);
+ }
+ }
+
+ @Override
+ public View onCreateView(
+ LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+
+ mView = inflater.inflate(R.layout.fragment_message_bar, container, false);
+
+ ImageView infoIcon = (ImageView) mView.findViewById(R.id.icon_info);
+ infoIcon.setImageResource(R.drawable.ic_dialog_info);
+
+ ImageView errorIcon = (ImageView) mView.findViewById(R.id.icon_error);
+ errorIcon.setImageResource(R.drawable.ic_dialog_alert);
+
+ Button dismiss = (Button) mView.findViewById(R.id.button_dismiss);
+ dismiss.setOnClickListener(
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ hide();
+ }
+ });
+
+ mContainer = container;
+
+ return mView;
+ }
+
+ void hide() {
+ // The container view is used to show/hide the error bar. If a container is not provided,
+ // fall back to showing/hiding the error bar View, which also works, but does not provide
+ // the same animated transition.
+ if (mContainer != null) {
+ mContainer.setVisibility(View.GONE);
+ } else {
+ mView.setVisibility(View.GONE);
+ }
+ }
+
+ void show() {
+ // The container view is used to show/hide the error bar. If a container is not provided,
+ // fall back to showing/hiding the error bar View, which also works, but does not provide
+ // the same animated transition.
+ if (mContainer != null) {
+ mContainer.setVisibility(View.VISIBLE);
+ } else {
+ mView.setVisibility(View.VISIBLE);
+ }
+ }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java b/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java
index 5930056f111c..858fb423fe06 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java
@@ -45,6 +45,8 @@ import android.view.View;
import com.android.documentsui.Events.InputEvent;
import com.android.documentsui.Events.MotionInputEvent;
+import com.google.android.collect.Lists;
+
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -113,8 +115,11 @@ public final class MultiSelectManager {
}
};
- CompositeOnGestureListener<? extends Object> compositeListener =
- new CompositeOnGestureListener<>(listener, gestureDelegate);
+ CompositeOnGestureListener compositeListener =
+ new CompositeOnGestureListener(
+ Lists.<OnGestureListener>newArrayList(listener, gestureDelegate),
+ Lists.<OnDoubleTapListener>newArrayList(listener, gestureDelegate));
+
final GestureDetector detector =
new GestureDetector(recyclerView.getContext(), compositeListener);
@@ -360,8 +365,8 @@ public final class MultiSelectManager {
// To make this more correct, we'd need to update the Ranger class to return
// information about what has changed.
notifySelectionChanged();
- } else if (toggleSelection(input.getItemPosition())) {
- notifySelectionChanged();
+ } else {
+ toggleSelection(input.getItemPosition());
}
}
@@ -370,14 +375,13 @@ public final class MultiSelectManager {
* a new Ranger (range selection manager) at that point is created.
*
* @param position
- * @return True if state changed.
*/
- private boolean toggleSelection(int position) {
+ private void toggleSelection(int position) {
// Position may be special "no position" during certain
// transitional phases. If so, skip handling of the event.
if (position == RecyclerView.NO_POSITION) {
if (DEBUG) Log.d(TAG, "Ignoring toggle for element with no position.");
- return false;
+ return;
}
boolean changed = false;
@@ -386,7 +390,7 @@ public final class MultiSelectManager {
} else {
boolean canSelect = notifyBeforeItemStateChange(position, true);
if (!canSelect) {
- return false;
+ return;
}
if (mSingleSelect && !mSelection.isEmpty()) {
clearSelectionQuietly();
@@ -402,7 +406,9 @@ public final class MultiSelectManager {
changed = true;
}
- return changed;
+ if (changed) {
+ notifySelectionChanged();
+ }
}
/**
@@ -1060,21 +1066,23 @@ public final class MultiSelectManager {
* @template A gestureDelegate that implements both {@link OnGestureListener}
* and {@link OnDoubleTapListener}
*/
- private static final class
- CompositeOnGestureListener<L extends OnGestureListener & OnDoubleTapListener>
+ private static final class CompositeOnGestureListener
implements OnGestureListener, OnDoubleTapListener {
- private L[] mListeners;
+ private List<OnGestureListener> mGestureListeners;
+ private List<OnDoubleTapListener> mTapListeners;
- @SafeVarargs
- public CompositeOnGestureListener(L... listeners) {
- mListeners = listeners;
+ public CompositeOnGestureListener(
+ List<OnGestureListener> gestureListeners,
+ List<OnDoubleTapListener> tapListeners) {
+ mGestureListeners = gestureListeners;
+ mTapListeners = tapListeners;
}
@Override
public boolean onDown(MotionEvent e) {
- for (int i = 0; i < mListeners.length; i++) {
- if (mListeners[i].onDown(e)) {
+ for (OnGestureListener l : mGestureListeners) {
+ if (l.onDown(e)) {
return true;
}
}
@@ -1083,15 +1091,15 @@ public final class MultiSelectManager {
@Override
public void onShowPress(MotionEvent e) {
- for (int i = 0; i < mListeners.length; i++) {
- mListeners[i].onShowPress(e);
+ for (OnGestureListener l : mGestureListeners) {
+ l.onShowPress(e);
}
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
- for (int i = 0; i < mListeners.length; i++) {
- if (mListeners[i].onSingleTapUp(e)) {
+ for (OnGestureListener l : mGestureListeners) {
+ if (l.onSingleTapUp(e)) {
return true;
}
}
@@ -1100,8 +1108,8 @@ public final class MultiSelectManager {
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
- for (int i = 0; i < mListeners.length; i++) {
- if (mListeners[i].onScroll(e1, e2, distanceX, distanceY)) {
+ for (OnGestureListener l : mGestureListeners) {
+ if (l.onScroll(e1, e2, distanceX, distanceY)) {
return true;
}
}
@@ -1110,15 +1118,15 @@ public final class MultiSelectManager {
@Override
public void onLongPress(MotionEvent e) {
- for (int i = 0; i < mListeners.length; i++) {
- mListeners[i].onLongPress(e);
+ for (OnGestureListener l : mGestureListeners) {
+ l.onLongPress(e);
}
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
- for (int i = 0; i < mListeners.length; i++) {
- if (mListeners[i].onFling(e1, e2, velocityX, velocityY)) {
+ for (OnGestureListener l : mGestureListeners) {
+ if (l.onFling(e1, e2, velocityX, velocityY)) {
return true;
}
}
@@ -1127,8 +1135,8 @@ public final class MultiSelectManager {
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
- for (int i = 0; i < mListeners.length; i++) {
- if (mListeners[i].onSingleTapConfirmed(e)) {
+ for (OnDoubleTapListener listener : mTapListeners) {
+ if (listener.onSingleTapConfirmed(e)) {
return true;
}
}
@@ -1137,8 +1145,8 @@ public final class MultiSelectManager {
@Override
public boolean onDoubleTap(MotionEvent e) {
- for (int i = 0; i < mListeners.length; i++) {
- if (mListeners[i].onDoubleTap(e)) {
+ for (OnDoubleTapListener listener : mTapListeners) {
+ if (listener.onDoubleTap(e)) {
return true;
}
}
@@ -1147,8 +1155,8 @@ public final class MultiSelectManager {
@Override
public boolean onDoubleTapEvent(MotionEvent e) {
- for (int i = 0; i < mListeners.length; i++) {
- if (mListeners[i].onDoubleTapEvent(e)) {
+ for (OnDoubleTapListener listener : mTapListeners) {
+ if (listener.onDoubleTapEvent(e)) {
return true;
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java b/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java
index 5f6a5e90e2c7..48e28dcfdd5c 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java
@@ -21,7 +21,6 @@ import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.os.Bundle;
-import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -29,8 +28,6 @@ import android.widget.Button;
import com.android.documentsui.model.DocumentInfo;
-import java.util.Locale;
-
/**
* Display pick confirmation bar, usually for selecting a directory.
*/
@@ -93,7 +90,7 @@ public class PickFragment extends Fragment {
};
/**
- * @param action Which action defined in BaseActivity.State is the picker shown for.
+ * @param action Which action defined in State is the picker shown for.
*/
public void setPickTarget(int action, int transferMode, DocumentInfo pickTarget) {
mAction = action;
@@ -109,11 +106,11 @@ public class PickFragment extends Fragment {
*/
private void updateView() {
switch (mAction) {
- case BaseActivity.State.ACTION_OPEN_TREE:
+ case State.ACTION_OPEN_TREE:
mPick.setText(R.string.button_select);
mCancel.setVisibility(View.GONE);
break;
- case BaseActivity.State.ACTION_OPEN_COPY_DESTINATION:
+ case State.ACTION_OPEN_COPY_DESTINATION:
mPick.setText(R.string.button_copy);
mCancel.setVisibility(View.VISIBLE);
break;
@@ -123,7 +120,7 @@ public class PickFragment extends Fragment {
}
if (mPickTarget != null && (
- mAction == BaseActivity.State.ACTION_OPEN_TREE ||
+ mAction == State.ACTION_OPEN_TREE ||
mPickTarget.isCreateSupported())) {
mContainer.setVisibility(View.VISIBLE);
} else {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java b/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java
index 4685c41fc2b6..607cb951bf3f 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java
@@ -16,6 +16,8 @@
package com.android.documentsui;
+import static com.android.documentsui.Shared.DEBUG;
+import static com.android.documentsui.Shared.TAG;
import static com.android.documentsui.model.DocumentInfo.getCursorString;
import android.content.ClipData;
@@ -38,9 +40,6 @@ import com.android.documentsui.model.DocumentInfo;
*/
final class QuickViewIntentBuilder {
- private static final String TAG = "QvIntentBuilder";
- private static final boolean DEBUG = false;
-
private final DocumentInfo mDocument;
private final DocumentContext mContext;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java b/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
index 1a7095a054c3..c2b64fb4317e 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
@@ -16,8 +16,9 @@
package com.android.documentsui;
-import static com.android.documentsui.BaseActivity.State.SORT_ORDER_LAST_MODIFIED;
+import static com.android.documentsui.Shared.DEBUG;
import static com.android.documentsui.Shared.TAG;
+import static com.android.documentsui.State.SORT_ORDER_LAST_MODIFIED;
import android.app.ActivityManager;
import android.content.AsyncTaskLoader;
@@ -34,7 +35,6 @@ import android.provider.DocumentsContract.Root;
import android.text.format.DateUtils;
import android.util.Log;
-import com.android.documentsui.BaseActivity.State;
import com.android.documentsui.model.RootInfo;
import com.google.common.util.concurrent.AbstractFuture;
@@ -53,8 +53,6 @@ import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
public class RecentLoader extends AsyncTaskLoader<DirectoryResult> {
- private static final boolean DEBUG = false;
-
// TODO: clean up cursor ownership so background thread doesn't traverse
// previously returned cursors for filtering/sorting; this currently races
// with the UI thread.
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
index 662822ee35d3..cf682fa508fc 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
@@ -30,22 +30,21 @@ import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.CancellationSignal;
+import android.support.annotation.Nullable;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.TextUtils.TruncateAt;
import android.text.style.ImageSpan;
import android.util.Log;
import android.view.LayoutInflater;
+import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemClickListener;
-import android.widget.BaseAdapter;
import android.widget.ImageView;
-import android.widget.ListView;
import android.widget.TextView;
-import com.android.documentsui.BaseActivity.State;
import com.android.documentsui.RecentsProvider.RecentColumns;
import com.android.documentsui.model.DocumentStack;
import com.android.documentsui.model.DurableUtils;
@@ -64,8 +63,7 @@ import java.util.List;
public class RecentsCreateFragment extends Fragment {
private View mEmptyView;
- private ListView mListView;
-
+ private RecyclerView mRecView;
private DocumentStackAdapter mAdapter;
private LoaderCallbacks<List<DocumentStack>> mCallbacks;
@@ -85,13 +83,14 @@ public class RecentsCreateFragment extends Fragment {
final View view = inflater.inflate(R.layout.fragment_directory, container, false);
- mEmptyView = view.findViewById(android.R.id.empty);
+ mRecView = (RecyclerView) view.findViewById(R.id.recyclerView);
+ mRecView.setLayoutManager(new LinearLayoutManager(getContext()));
+ mRecView.addOnItemTouchListener(mItemListener);
- mListView = (ListView) view.findViewById(R.id.list);
- mListView.setOnItemClickListener(mItemListener);
+ mEmptyView = view.findViewById(android.R.id.empty);
mAdapter = new DocumentStackAdapter();
- mListView.setAdapter(mAdapter);
+ mRecView.setAdapter(mAdapter);
final RootsCache roots = DocumentsApplication.getRootsCache(context);
final State state = ((BaseActivity) getActivity()).getDisplayState();
@@ -105,7 +104,7 @@ public class RecentsCreateFragment extends Fragment {
@Override
public void onLoadFinished(
Loader<List<DocumentStack>> loader, List<DocumentStack> data) {
- mAdapter.swapStacks(data);
+ mAdapter.update(data);
// When launched into empty recents, show drawer
if (mAdapter.isEmpty() && !state.stackTouched &&
@@ -116,7 +115,7 @@ public class RecentsCreateFragment extends Fragment {
@Override
public void onLoaderReset(Loader<List<DocumentStack>> loader) {
- mAdapter.swapStacks(null);
+ mAdapter.update(null);
}
};
@@ -135,13 +134,24 @@ public class RecentsCreateFragment extends Fragment {
getLoaderManager().destroyLoader(LOADER_RECENTS);
}
- private OnItemClickListener mItemListener = new OnItemClickListener() {
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- final DocumentStack stack = mAdapter.getItem(position);
- ((BaseActivity) getActivity()).onStackPicked(stack);
- }
- };
+ private RecyclerView.OnItemTouchListener mItemListener =
+ new RecyclerView.OnItemTouchListener() {
+ @Override
+ public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
+ Events.MotionInputEvent event = new Events.MotionInputEvent(e, mRecView);
+ if (event.isOverItem() && event.isActionUp()) {
+ final DocumentStack stack = mAdapter.getItem(event.getItemPosition());
+ ((BaseActivity) getActivity()).onStackPicked(stack);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void onTouchEvent(RecyclerView rv, MotionEvent e) {}
+ @Override
+ public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {}
+ };
public static class RecentsCreateLoader extends UriDerivativeLoader<Uri, List<DocumentStack>> {
private final RootsCache mRoots;
@@ -187,14 +197,32 @@ public class RecentsCreateFragment extends Fragment {
}
}
- private class DocumentStackAdapter extends BaseAdapter {
- private List<DocumentStack> mStacks;
+ private static final class StackHolder extends RecyclerView.ViewHolder {
+ public View view;
+ public StackHolder(View view) {
+ super(view);
+ this.view = view;
+ }
+ }
+
+ private class DocumentStackAdapter extends RecyclerView.Adapter<StackHolder> {
+ @Nullable private List<DocumentStack> mItems;
+
+ DocumentStack getItem(int position) {
+ return mItems.get(position);
+ }
+
+ @Override
+ public int getItemCount() {
+ return mItems == null ? 0 : mItems.size();
+ }
- public DocumentStackAdapter() {
+ boolean isEmpty() {
+ return mItems == null ? true : mItems.isEmpty();
}
- public void swapStacks(List<DocumentStack> stacks) {
- mStacks = stacks;
+ void update(@Nullable List<DocumentStack> items) {
+ mItems = items;
if (isEmpty()) {
mEmptyView.setVisibility(View.VISIBLE);
@@ -206,17 +234,22 @@ public class RecentsCreateFragment extends Fragment {
}
@Override
- public View getView(int position, View convertView, ViewGroup parent) {
- final Context context = parent.getContext();
+ public StackHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ final Context context = parent.getContext();
- if (convertView == null) {
- final LayoutInflater inflater = LayoutInflater.from(context);
- convertView = inflater.inflate(R.layout.item_doc_list, parent, false);
- }
+ final LayoutInflater inflater = LayoutInflater.from(context);
+ return new StackHolder(
+ (View) inflater.inflate(R.layout.item_doc_list, parent, false));
+ }
+
+ @Override
+ public void onBindViewHolder(StackHolder holder, int position) {
+ Context context = getContext();
+ View view = holder.view;
- final ImageView iconMime = (ImageView) convertView.findViewById(R.id.icon_mime);
- final TextView title = (TextView) convertView.findViewById(android.R.id.title);
- final View line2 = convertView.findViewById(R.id.line2);
+ final ImageView iconMime = (ImageView) view.findViewById(R.id.icon_mime);
+ final TextView title = (TextView) view.findViewById(android.R.id.title);
+ final View line2 = view.findViewById(R.id.line2);
final DocumentStack stack = getItem(position);
iconMime.setImageDrawable(stack.root.loadIcon(context));
@@ -234,23 +267,6 @@ public class RecentsCreateFragment extends Fragment {
title.setEllipsize(TruncateAt.MIDDLE);
if (line2 != null) line2.setVisibility(View.GONE);
-
- return convertView;
- }
-
- @Override
- public int getCount() {
- return mStacks != null ? mStacks.size() : 0;
- }
-
- @Override
- public DocumentStack getItem(int position) {
- return mStacks.get(position);
- }
-
- @Override
- public long getItemId(int position) {
- return getItem(position).hashCode();
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
index f6e434966a8a..82eb732002bb 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
@@ -39,6 +39,7 @@ import android.util.Log;
import com.android.documentsui.model.DocumentStack;
import com.android.documentsui.model.DurableUtils;
import com.android.internal.util.Predicate;
+
import com.google.android.collect.Sets;
import libcore.io.IoUtils;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
index 05f7d8dd11e3..de35cef6ddb6 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
@@ -16,6 +16,7 @@
package com.android.documentsui;
+import static com.android.documentsui.Shared.DEBUG;
import static com.android.documentsui.Shared.TAG;
import android.content.ContentProviderClient;
@@ -34,12 +35,11 @@ import android.os.Handler;
import android.os.SystemClock;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Root;
+import android.support.annotation.VisibleForTesting;
import android.util.Log;
-import com.android.documentsui.BaseActivity.State;
import com.android.documentsui.model.RootInfo;
import com.android.internal.annotations.GuardedBy;
-import android.support.annotation.VisibleForTesting;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
@@ -58,8 +58,6 @@ import java.util.concurrent.TimeUnit;
* Cache of known storage backends and their roots.
*/
public class RootsCache {
- private static final boolean LOGD = false;
-
public static final Uri sNotificationUri = Uri.parse(
"content://com.android.documentsui.roots/");
@@ -91,7 +89,7 @@ public class RootsCache {
@Override
public void onChange(boolean selfChange, Uri uri) {
- if (LOGD) Log.d(TAG, "Updating roots due to change at " + uri);
+ if (DEBUG) Log.d(TAG, "Updating roots due to change at " + uri);
updateAuthorityAsync(uri.getAuthority());
}
}
@@ -148,7 +146,7 @@ public class RootsCache {
final ContentResolver resolver = mContext.getContentResolver();
synchronized (mLock) {
for (String authority : mStoppedAuthorities) {
- if (LOGD) Log.d(TAG, "Loading stopped authority " + authority);
+ if (DEBUG) Log.d(TAG, "Loading stopped authority " + authority);
mRoots.putAll(authority, loadRootsForAuthority(resolver, authority));
}
mStoppedAuthorities.clear();
@@ -199,7 +197,8 @@ public class RootsCache {
}
final long delta = SystemClock.elapsedRealtime() - start;
- Log.d(TAG, "Update found " + mTaskRoots.size() + " roots in " + delta + "ms");
+ if (DEBUG)
+ Log.d(TAG, "Update found " + mTaskRoots.size() + " roots in " + delta + "ms");
synchronized (mLock) {
mRoots = mTaskRoots;
mStoppedAuthorities = mTaskStoppedAuthorities;
@@ -213,7 +212,7 @@ public class RootsCache {
// Ignore stopped packages for now; we might query them
// later during UI interaction.
if ((info.applicationInfo.flags & ApplicationInfo.FLAG_STOPPED) != 0) {
- if (LOGD) Log.d(TAG, "Ignoring stopped authority " + info.authority);
+ if (DEBUG) Log.d(TAG, "Ignoring stopped authority " + info.authority);
mTaskStoppedAuthorities.add(info.authority);
return;
}
@@ -223,7 +222,7 @@ public class RootsCache {
if (mFilterPackage != null && !mFilterPackage.equals(info.packageName)) {
synchronized (mLock) {
if (mTaskRoots.putAll(info.authority, mRoots.get(info.authority))) {
- if (LOGD) Log.d(TAG, "Used cached roots for " + info.authority);
+ if (DEBUG) Log.d(TAG, "Used cached roots for " + info.authority);
cacheHit = true;
}
}
@@ -241,7 +240,7 @@ public class RootsCache {
* Bring up requested provider and query for all active roots.
*/
private Collection<RootInfo> loadRootsForAuthority(ContentResolver resolver, String authority) {
- if (LOGD) Log.d(TAG, "Loading roots for " + authority);
+ if (DEBUG) Log.d(TAG, "Loading roots for " + authority);
synchronized (mObservedAuthorities) {
if (mObservedAuthorities.add(authority)) {
@@ -370,10 +369,13 @@ public class RootsCache {
// Exclude downloads roots that don't support directory creation
// TODO: Add flag to check the root supports directory creation or not.
if (state.directoryCopy && root.isDownloads()) continue;
- // Only show empty roots when creating
- if ((state.action != State.ACTION_CREATE ||
- state.action != State.ACTION_OPEN_TREE ||
- state.action != State.ACTION_OPEN_COPY_DESTINATION) && empty) continue;
+
+ // Only show empty roots when creating, or in browse mode.
+ if (empty && (state.action == State.ACTION_OPEN
+ || state.action == State.ACTION_GET_CONTENT)) {
+ if (DEBUG) Log.i(TAG, "Skipping empty root: " + root);
+ continue;
+ }
// Only include roots that serve requested content
final boolean overlap =
@@ -385,7 +387,7 @@ public class RootsCache {
// Exclude roots from the calling package.
if (state.excludedAuthorities.contains(root.authority)) {
- if (LOGD) Log.d(TAG, "Excluding root " + root.authority + " from calling package.");
+ if (DEBUG) Log.d(TAG, "Excluding root " + root.authority + " from calling package.");
continue;
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
index c02184b72b2f..c98da471cd88 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
@@ -41,7 +41,6 @@ import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
-import com.android.documentsui.BaseActivity.State;
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.RootInfo;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsLoader.java b/packages/DocumentsUI/src/com/android/documentsui/RootsLoader.java
index 49651b4dc50b..c81377a19aa2 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsLoader.java
@@ -19,7 +19,6 @@ package com.android.documentsui;
import android.content.AsyncTaskLoader;
import android.content.Context;
-import com.android.documentsui.BaseActivity.State;
import com.android.documentsui.model.RootInfo;
import java.util.Collection;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Shared.java b/packages/DocumentsUI/src/com/android/documentsui/Shared.java
index 0c1ebc16f1df..9c884d4ef8c6 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/Shared.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/Shared.java
@@ -22,7 +22,7 @@ import android.content.Context;
* @hide
*/
public final class Shared {
- public static final boolean DEBUG = false;
+ public static final boolean DEBUG = true;
public static final String TAG = "Documents";
/**
diff --git a/packages/DocumentsUI/src/com/android/documentsui/SortingCursorWrapper.java b/packages/DocumentsUI/src/com/android/documentsui/SortingCursorWrapper.java
index 3ec3d1c01062..6698ff159f25 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/SortingCursorWrapper.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/SortingCursorWrapper.java
@@ -16,9 +16,9 @@
package com.android.documentsui;
-import static com.android.documentsui.BaseActivity.State.SORT_ORDER_DISPLAY_NAME;
-import static com.android.documentsui.BaseActivity.State.SORT_ORDER_LAST_MODIFIED;
-import static com.android.documentsui.BaseActivity.State.SORT_ORDER_SIZE;
+import static com.android.documentsui.State.SORT_ORDER_DISPLAY_NAME;
+import static com.android.documentsui.State.SORT_ORDER_LAST_MODIFIED;
+import static com.android.documentsui.State.SORT_ORDER_SIZE;
import static com.android.documentsui.model.DocumentInfo.getCursorLong;
import static com.android.documentsui.model.DocumentInfo.getCursorString;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/State.java b/packages/DocumentsUI/src/com/android/documentsui/State.java
new file mode 100644
index 000000000000..4306a0e024a2
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/State.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui;
+
+import android.content.Intent;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.SparseArray;
+
+import com.android.documentsui.model.DocumentInfo;
+import com.android.documentsui.model.DocumentStack;
+import com.android.documentsui.model.DurableUtils;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+public class State implements android.os.Parcelable {
+ public int action;
+ public String[] acceptMimes;
+
+ /** Explicit user choice */
+ public int userMode = MODE_UNKNOWN;
+ /** Derived after loader */
+ public int derivedMode = MODE_LIST;
+
+ /** Explicit user choice */
+ public int userSortOrder = SORT_ORDER_UNKNOWN;
+ /** Derived after loader */
+ public int derivedSortOrder = SORT_ORDER_DISPLAY_NAME;
+
+ public boolean allowMultiple;
+ public boolean forceSize;
+ public boolean showSize;
+ 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;
+
+ /** Current user navigation stack; empty implies recents. */
+ public DocumentStack stack = new DocumentStack();
+ /** Currently active search, overriding any stack. */
+ public String currentSearch;
+
+ /** Instance state for every shown directory */
+ public HashMap<String, SparseArray<Parcelable>> dirState = new HashMap<>();
+
+ /** Currently copying file */
+ public List<DocumentInfo> selectedDocumentsForCopy = new ArrayList<DocumentInfo>();
+
+ /** Name of the package that started DocsUI */
+ public List<String> excludedAuthorities = new ArrayList<>();
+
+ public static final int ACTION_OPEN = 1;
+ public static final int ACTION_CREATE = 2;
+ public static final int ACTION_GET_CONTENT = 3;
+ public static final int ACTION_OPEN_TREE = 4;
+ public static final int ACTION_MANAGE = 5;
+ public static final int ACTION_BROWSE = 6;
+ public static final int ACTION_OPEN_COPY_DESTINATION = 8;
+
+ public static final int MODE_UNKNOWN = 0;
+ public static final int MODE_LIST = 1;
+ public static final int MODE_GRID = 2;
+
+ public static final int SORT_ORDER_UNKNOWN = 0;
+ public static final int SORT_ORDER_DISPLAY_NAME = 1;
+ public static final int SORT_ORDER_LAST_MODIFIED = 2;
+ public static final int SORT_ORDER_SIZE = 3;
+
+ public void initAcceptMimes(Intent intent) {
+ if (intent.hasExtra(Intent.EXTRA_MIME_TYPES)) {
+ acceptMimes = intent.getStringArrayExtra(Intent.EXTRA_MIME_TYPES);
+ } else {
+ String glob = intent.getType();
+ acceptMimes = new String[] { glob != null ? glob : "*/*" };
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(action);
+ out.writeInt(userMode);
+ out.writeStringArray(acceptMimes);
+ out.writeInt(userSortOrder);
+ out.writeInt(allowMultiple ? 1 : 0);
+ out.writeInt(forceSize ? 1 : 0);
+ out.writeInt(showSize ? 1 : 0);
+ out.writeInt(localOnly ? 1 : 0);
+ out.writeInt(forceAdvanced ? 1 : 0);
+ out.writeInt(showAdvanced ? 1 : 0);
+ out.writeInt(stackTouched ? 1 : 0);
+ out.writeInt(restored ? 1 : 0);
+ DurableUtils.writeToParcel(out, stack);
+ out.writeString(currentSearch);
+ out.writeMap(dirState);
+ out.writeList(selectedDocumentsForCopy);
+ out.writeList(excludedAuthorities);
+ }
+
+ public static final Creator<State> CREATOR = new Creator<State>() {
+ @Override
+ public State createFromParcel(Parcel in) {
+ final State state = new State();
+ state.action = in.readInt();
+ state.userMode = in.readInt();
+ state.acceptMimes = in.readStringArray();
+ state.userSortOrder = in.readInt();
+ state.allowMultiple = in.readInt() != 0;
+ state.forceSize = in.readInt() != 0;
+ state.showSize = in.readInt() != 0;
+ state.localOnly = in.readInt() != 0;
+ state.forceAdvanced = in.readInt() != 0;
+ state.showAdvanced = in.readInt() != 0;
+ state.stackTouched = in.readInt() != 0;
+ state.restored = in.readInt() != 0;
+ DurableUtils.readFromParcel(in, state.stack);
+ state.currentSearch = in.readString();
+ in.readMap(state.dirState, null);
+ in.readList(state.selectedDocumentsForCopy, null);
+ in.readList(state.excludedAuthorities, null);
+ return state;
+ }
+
+ @Override
+ public State[] newArray(int size) {
+ return new State[size];
+ }
+ };
+} \ No newline at end of file
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/DirectoryFragmentModelTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/DirectoryFragmentModelTest.java
index 5505f3546e5d..1895a6e66450 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/DirectoryFragmentModelTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/DirectoryFragmentModelTest.java
@@ -22,9 +22,12 @@ import android.content.ContextWrapper;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.provider.DocumentsContract.Document;
+import android.support.v7.widget.RecyclerView.ViewHolder;
+import android.support.v7.widget.RecyclerView;
import android.test.AndroidTestCase;
import android.test.MoreAsserts;
import android.test.mock.MockContentResolver;
+import android.view.ViewGroup;
import com.android.documentsui.DirectoryFragment.Model;
import com.android.documentsui.MultiSelectManager.Selection;
@@ -57,7 +60,8 @@ public class DirectoryFragmentModelTest extends AndroidTestCase {
DirectoryResult r = new DirectoryResult();
r.cursor = cursor;
- model = new Model(mContext, null);
+ // Instantiate the model with a dummy view adapter and listener that (for now) do nothing.
+ model = new Model(mContext, null, new DummyAdapter());
model.addUpdateListener(new DummyListener());
model.update(r);
}
@@ -160,11 +164,16 @@ public class DirectoryFragmentModelTest extends AndroidTestCase {
return model.getDocuments(sel);
}
- private static class DummyListener implements Model.UpdateListener {
+ private static class DummyListener extends Model.UpdateListener {
public void onModelUpdate(Model model) {}
public void onModelUpdateFailed(Exception e) {}
- public void notifyItemRemoved(int position) {}
- public void notifyItemInserted(int position) {}
}
+ private static class DummyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
+ public int getItemCount() { return 0; }
+ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {}
+ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ return null;
+ }
+ }
}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java
index 132570674b48..7d3498e4e079 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java
@@ -19,7 +19,6 @@ package com.android.documentsui;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
-import com.android.documentsui.BaseActivity.State;
import com.android.documentsui.model.RootInfo;
import com.google.common.collect.Lists;
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java
index aeac91215be6..2033159af720 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java
@@ -23,6 +23,7 @@ import com.android.internal.telephony.PhoneConstants;
import android.content.Context;
import android.content.res.ColorStateList;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
@@ -96,6 +97,12 @@ public class KeyguardSimPinView extends KeyguardPinBasedInputView {
}
@Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ resetState();
+ }
+
+ @Override
protected int getPromtReasonStringRes(int reason) {
// No message on SIM Pin
return 0;
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 47d8e283257b..57ee319f8ff3 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -121,7 +121,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
private static final int MSG_DEVICE_PROVISIONED = 308;
private static final int MSG_DPM_STATE_CHANGED = 309;
private static final int MSG_USER_SWITCHING = 310;
- private static final int MSG_KEYGUARD_VISIBILITY_CHANGED = 311;
private static final int MSG_KEYGUARD_RESET = 312;
private static final int MSG_BOOT_COMPLETED = 313;
private static final int MSG_USER_SWITCH_COMPLETE = 314;
@@ -129,6 +128,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
private static final int MSG_REPORT_EMERGENCY_CALL_ACTION = 318;
private static final int MSG_STARTED_WAKING_UP = 319;
private static final int MSG_FINISHED_GOING_TO_SLEEP = 320;
+ private static final int MSG_STARTED_GOING_TO_SLEEP = 321;
private static final int MSG_KEYGUARD_BOUNCER_CHANGED = 322;
private static final int MSG_FACE_UNLOCK_STATE_CHANGED = 327;
private static final int MSG_SIM_SUBSCRIPTION_INFO_CHANGED = 328;
@@ -170,6 +170,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
* until the Keyguard has been dismissed.
*/
private boolean mFingerprintAlreadyAuthenticated;
+ private boolean mGoingToSleep;
private boolean mBouncer;
private boolean mBootCompleted;
@@ -231,9 +232,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
case MSG_USER_SWITCH_COMPLETE:
handleUserSwitchComplete(msg.arg1);
break;
- case MSG_KEYGUARD_VISIBILITY_CHANGED:
- handleKeyguardVisibilityChanged(msg.arg1);
- break;
case MSG_KEYGUARD_RESET:
handleKeyguardReset();
break;
@@ -249,6 +247,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
case MSG_REPORT_EMERGENCY_CALL_ACTION:
handleReportEmergencyCallAction();
break;
+ case MSG_STARTED_GOING_TO_SLEEP:
+ handleStartedGoingToSleep(msg.arg1);
+ break;
case MSG_FINISHED_GOING_TO_SLEEP:
handleFinishedGoingToSleep(msg.arg1);
break;
@@ -884,19 +885,32 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
}
}
- protected void handleFinishedGoingToSleep(int arg1) {
+ protected void handleStartedGoingToSleep(int arg1) {
clearFingerprintRecognized();
final int count = mCallbacks.size();
for (int i = 0; i < count; i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
- cb.onFinishedGoingToSleep(arg1);
+ cb.onStartedGoingToSleep(arg1);
}
}
+ mGoingToSleep = true;
mFingerprintAlreadyAuthenticated = false;
updateFingerprintListeningState();
}
+ protected void handleFinishedGoingToSleep(int arg1) {
+ mGoingToSleep = false;
+ final int count = mCallbacks.size();
+ for (int i = 0; i < count; i++) {
+ KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+ if (cb != null) {
+ cb.onFinishedGoingToSleep(arg1);
+ }
+ }
+ updateFingerprintListeningState();
+ }
+
private void handleScreenTurnedOn() {
final int count = mCallbacks.size();
for (int i = 0; i < count; i++) {
@@ -1032,8 +1046,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
}
private boolean shouldListenForFingerprint() {
- return (mKeyguardIsVisible || !mDeviceInteractive || mBouncer) && !mSwitchingUser
- && !mFingerprintAlreadyAuthenticated && !isFingerprintDisabled(getCurrentUser());
+ return (mKeyguardIsVisible || !mDeviceInteractive || mBouncer || mGoingToSleep)
+ && !mSwitchingUser && !mFingerprintAlreadyAuthenticated
+ && !isFingerprintDisabled(getCurrentUser());
}
private void startListeningForFingerprint() {
@@ -1325,19 +1340,20 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
}
/**
- * Handle {@link #MSG_KEYGUARD_VISIBILITY_CHANGED}
+ * Notifies that the visibility state of Keyguard has changed.
+ *
+ * <p>Needs to be called from the main thread.
*/
- private void handleKeyguardVisibilityChanged(int showing) {
- if (DEBUG) Log.d(TAG, "handleKeyguardVisibilityChanged(" + showing + ")");
- boolean isShowing = (showing == 1);
- mKeyguardIsVisible = isShowing;
+ public void onKeyguardVisibilityChanged(boolean showing) {
+ if (DEBUG) Log.d(TAG, "onKeyguardVisibilityChanged(" + showing + ")");
+ mKeyguardIsVisible = showing;
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
- cb.onKeyguardVisibilityChangedRaw(isShowing);
+ cb.onKeyguardVisibilityChangedRaw(showing);
}
}
- if (!isShowing) {
+ if (!showing) {
mFingerprintAlreadyAuthenticated = false;
}
updateFingerprintListeningState();
@@ -1458,13 +1474,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
}
}
- public void sendKeyguardVisibilityChanged(boolean showing) {
- if (DEBUG) Log.d(TAG, "sendKeyguardVisibilityChanged(" + showing + ")");
- Message message = mHandler.obtainMessage(MSG_KEYGUARD_VISIBILITY_CHANGED);
- message.arg1 = showing ? 1 : 0;
- message.sendToTarget();
- }
-
public void sendKeyguardReset() {
mHandler.obtainMessage(MSG_KEYGUARD_RESET).sendToTarget();
}
@@ -1605,6 +1614,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
mHandler.sendEmptyMessage(MSG_STARTED_WAKING_UP);
}
+ public void dispatchStartedGoingToSleep(int why) {
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_STARTED_GOING_TO_SLEEP, why, 0));
+ }
+
public void dispatchFinishedGoingToSleep(int why) {
synchronized(this) {
mDeviceInteractive = false;
@@ -1630,6 +1643,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
return mDeviceInteractive;
}
+ public boolean isGoingToSleep() {
+ return mGoingToSleep;
+ }
+
/**
* Find the next SubscriptionId for a SIM in the given state, favoring lower slot numbers first.
* @param state
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index 15ffe9f5ca7e..bd6c51c3b89c 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -153,6 +153,12 @@ public class KeyguardUpdateMonitorCallback {
public void onStartedWakingUp() { }
/**
+ * Called when the device has started going to sleep.
+ * @param why see {@link #onFinishedGoingToSleep(int)}
+ */
+ public void onStartedGoingToSleep(int why) { }
+
+ /**
* Called when the device has finished going to sleep.
* @param why either {@link WindowManagerPolicy#OFF_BECAUSE_OF_ADMIN},
* {@link WindowManagerPolicy#OFF_BECAUSE_OF_USER}, or
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java b/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java
index d4c4331267a0..0d4265a6417c 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java
@@ -91,12 +91,12 @@ class DocumentLoader {
return task.createCursor(mResolver, columnNames);
}
- synchronized void clearTasks(int deviceId) {
- mTaskList.clearTaskForDevice(deviceId);
+ synchronized void clearTasks() {
+ mTaskList.clear();
}
synchronized void clearCompletedTasks() {
- mTaskList.clearCompletedTask();
+ mTaskList.clearCompletedTasks();
}
synchronized void clearTask(Identifier parentIdentifier) {
@@ -162,18 +162,7 @@ class DocumentLoader {
return null;
}
- void clearTaskForDevice(int deviceId) {
- int i = 0;
- while (i < size()) {
- if (get(i).mIdentifier.mDeviceId == deviceId) {
- remove(i);
- } else {
- i++;
- }
- }
- }
-
- void clearCompletedTask() {
+ void clearCompletedTasks() {
int i = 0;
while (i < size()) {
if (get(i).completed()) {
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
index 78ed161d47f4..a1a43c18a72f 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
@@ -34,6 +34,8 @@ import com.android.internal.annotations.VisibleForTesting;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
/**
* DocumentsProvider for MTP devices.
@@ -56,8 +58,8 @@ public class MtpDocumentsProvider extends DocumentsProvider {
private MtpManager mMtpManager;
private ContentResolver mResolver;
- private PipeManager mPipeManager;
- private DocumentLoader mDocumentLoader;
+ private Map<Integer, DeviceToolkit> mDeviceToolkits;
+ private DocumentLoader mDocumentLoaders;
private RootScanner mRootScanner;
/**
@@ -72,8 +74,7 @@ public class MtpDocumentsProvider extends DocumentsProvider {
sSingleton = this;
mMtpManager = new MtpManager(getContext());
mResolver = getContext().getContentResolver();
- mPipeManager = new PipeManager();
- mDocumentLoader = new DocumentLoader(mMtpManager, mResolver);
+ mDeviceToolkits = new HashMap<Integer, DeviceToolkit>();
mRootScanner = new RootScanner(mResolver, mMtpManager);
return true;
}
@@ -82,7 +83,7 @@ public class MtpDocumentsProvider extends DocumentsProvider {
void onCreateForTesting(MtpManager mtpManager, ContentResolver resolver) {
mMtpManager = mtpManager;
mResolver = resolver;
- mDocumentLoader = new DocumentLoader(mMtpManager, mResolver);
+ mDeviceToolkits = new HashMap<Integer, DeviceToolkit>();
mRootScanner = new RootScanner(mResolver, mMtpManager);
}
@@ -158,7 +159,8 @@ public class MtpDocumentsProvider extends DocumentsProvider {
}
final Identifier parentIdentifier = Identifier.createFromDocumentId(parentDocumentId);
try {
- return mDocumentLoader.queryChildDocuments(projection, parentIdentifier);
+ return getDocumentLoader(parentIdentifier).queryChildDocuments(
+ projection, parentIdentifier);
} catch (IOException exception) {
throw new FileNotFoundException(exception.getMessage());
}
@@ -172,11 +174,12 @@ public class MtpDocumentsProvider extends DocumentsProvider {
try {
switch (mode) {
case "r":
- return mPipeManager.readDocument(mMtpManager, identifier);
+ return getPipeManager(identifier).readDocument(mMtpManager, identifier);
case "w":
// TODO: Clear the parent document loader task (if exists) and call notify
// when writing is completed.
- return mPipeManager.writeDocument(getContext(), mMtpManager, identifier);
+ return getPipeManager(identifier).writeDocument(
+ getContext(), mMtpManager, identifier);
default:
// TODO: Add support for seekable files.
throw new UnsupportedOperationException(
@@ -195,7 +198,7 @@ public class MtpDocumentsProvider extends DocumentsProvider {
final Identifier identifier = Identifier.createFromDocumentId(documentId);
try {
return new AssetFileDescriptor(
- mPipeManager.readThumbnail(mMtpManager, identifier),
+ getPipeManager(identifier).readThumbnail(mMtpManager, identifier),
0, // Start offset.
AssetFileDescriptor.UNKNOWN_LENGTH);
} catch (IOException error) {
@@ -212,7 +215,7 @@ public class MtpDocumentsProvider extends DocumentsProvider {
mMtpManager.deleteDocument(identifier.mDeviceId, identifier.mObjectHandle);
final Identifier parentIdentifier = new Identifier(
identifier.mDeviceId, identifier.mStorageId, parentHandle);
- mDocumentLoader.clearTask(parentIdentifier);
+ getDocumentLoader(parentIdentifier).clearTask(parentIdentifier);
notifyChildDocumentsChange(parentIdentifier.toDocumentId());
} catch (IOException error) {
throw new FileNotFoundException(error.getMessage());
@@ -221,7 +224,9 @@ public class MtpDocumentsProvider extends DocumentsProvider {
@Override
public void onTrimMemory(int level) {
- mDocumentLoader.clearCompletedTasks();
+ for (final DeviceToolkit toolkit : mDeviceToolkits.values()) {
+ toolkit.mDocumentLoader.clearCompletedTasks();
+ }
}
@Override
@@ -241,7 +246,7 @@ public class MtpDocumentsProvider extends DocumentsProvider {
.build(), pipe[1]);
final String documentId = new Identifier(parentId.mDeviceId, parentId.mStorageId,
objectHandle).toDocumentId();
- mDocumentLoader.clearTask(parentId);
+ getDocumentLoader(parentId).clearTask(parentId);
notifyChildDocumentsChange(parentDocumentId);
return documentId;
} catch (IOException error) {
@@ -252,12 +257,15 @@ public class MtpDocumentsProvider extends DocumentsProvider {
void openDevice(int deviceId) throws IOException {
mMtpManager.openDevice(deviceId);
+ mDeviceToolkits.put(deviceId, new DeviceToolkit(mMtpManager, mResolver));
mRootScanner.scanNow();
}
void closeDevice(int deviceId) throws IOException {
+ // TODO: Flush the device before closing (if not closed externally).
+ getDeviceToolkit(deviceId).mDocumentLoader.clearTasks();
+ mDeviceToolkits.remove(deviceId);
mMtpManager.closeDevice(deviceId);
- mDocumentLoader.clearTasks(deviceId);
mRootScanner.scanNow();
}
@@ -266,7 +274,7 @@ public class MtpDocumentsProvider extends DocumentsProvider {
for (int deviceId : mMtpManager.getOpenedDeviceIds()) {
try {
mMtpManager.closeDevice(deviceId);
- mDocumentLoader.clearTasks(deviceId);
+ getDeviceToolkit(deviceId).mDocumentLoader.clearTasks();
closed = true;
} catch (IOException d) {
Log.d(TAG, "Failed to close the MTP device: " + deviceId);
@@ -287,4 +295,30 @@ public class MtpDocumentsProvider extends DocumentsProvider {
null,
false);
}
+
+ private DeviceToolkit getDeviceToolkit(int deviceId) throws FileNotFoundException {
+ final DeviceToolkit toolkit = mDeviceToolkits.get(deviceId);
+ if (toolkit == null) {
+ throw new FileNotFoundException();
+ }
+ return toolkit;
+ }
+
+ private PipeManager getPipeManager(Identifier identifier) throws FileNotFoundException {
+ return getDeviceToolkit(identifier.mDeviceId).mPipeManager;
+ }
+
+ private DocumentLoader getDocumentLoader(Identifier identifier) throws FileNotFoundException {
+ return getDeviceToolkit(identifier.mDeviceId).mDocumentLoader;
+ }
+
+ private static class DeviceToolkit {
+ public final PipeManager mPipeManager;
+ public final DocumentLoader mDocumentLoader;
+
+ public DeviceToolkit(MtpManager manager, ContentResolver resolver) {
+ mPipeManager = new PipeManager();
+ mDocumentLoader = new DocumentLoader(manager, resolver);
+ }
+ }
}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
index ca78a3e1b775..7cc7413bab3d 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
@@ -42,7 +42,7 @@ class MtpManager {
private final SparseArray<MtpDevice> mDevices = new SparseArray<>();
MtpManager(Context context) {
- mManager = (UsbManager)context.getSystemService(Context.USB_SERVICE);
+ mManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
}
synchronized void openDevice(int deviceId) throws IOException {
@@ -96,78 +96,96 @@ class MtpManager {
return result;
}
- synchronized MtpRoot[] getRoots(int deviceId) throws IOException {
+ MtpRoot[] getRoots(int deviceId) throws IOException {
final MtpDevice device = getDevice(deviceId);
- final int[] storageIds = device.getStorageIds();
- if (storageIds == null) {
- throw new IOException("Failed to obtain storage IDs.");
- }
- final MtpRoot[] results = new MtpRoot[storageIds.length];
- for (int i = 0; i < storageIds.length; i++) {
- results[i] = new MtpRoot(deviceId, device.getStorageInfo(storageIds[i]));
+ synchronized (device) {
+ final int[] storageIds = device.getStorageIds();
+ if (storageIds == null) {
+ throw new IOException("Failed to obtain storage IDs.");
+ }
+ final MtpRoot[] results = new MtpRoot[storageIds.length];
+ for (int i = 0; i < storageIds.length; i++) {
+ results[i] = new MtpRoot(deviceId, device.getStorageInfo(storageIds[i]));
+ }
+ return results;
}
- return results;
}
- synchronized MtpObjectInfo getObjectInfo(int deviceId, int objectHandle)
+ MtpObjectInfo getObjectInfo(int deviceId, int objectHandle)
throws IOException {
final MtpDevice device = getDevice(deviceId);
- return device.getObjectInfo(objectHandle);
+ synchronized (device) {
+ return device.getObjectInfo(objectHandle);
+ }
}
- synchronized int[] getObjectHandles(int deviceId, int storageId, int parentObjectHandle)
+ int[] getObjectHandles(int deviceId, int storageId, int parentObjectHandle)
throws IOException {
final MtpDevice device = getDevice(deviceId);
- return device.getObjectHandles(storageId, 0 /* all format */, parentObjectHandle);
+ synchronized (device) {
+ return device.getObjectHandles(storageId, 0 /* all format */, parentObjectHandle);
+ }
}
- synchronized byte[] getObject(int deviceId, int objectHandle, int expectedSize)
+ byte[] getObject(int deviceId, int objectHandle, int expectedSize)
throws IOException {
final MtpDevice device = getDevice(deviceId);
- return device.getObject(objectHandle, expectedSize);
+ synchronized (device) {
+ return device.getObject(objectHandle, expectedSize);
+ }
}
- synchronized byte[] getThumbnail(int deviceId, int objectHandle) throws IOException {
+ byte[] getThumbnail(int deviceId, int objectHandle) throws IOException {
final MtpDevice device = getDevice(deviceId);
- return device.getThumbnail(objectHandle);
+ synchronized (device) {
+ return device.getThumbnail(objectHandle);
+ }
}
- synchronized void deleteDocument(int deviceId, int objectHandle) throws IOException {
+ void deleteDocument(int deviceId, int objectHandle) throws IOException {
final MtpDevice device = getDevice(deviceId);
- if (!device.deleteObject(objectHandle)) {
- throw new IOException("Failed to delete document");
+ synchronized (device) {
+ if (!device.deleteObject(objectHandle)) {
+ throw new IOException("Failed to delete document");
+ }
}
}
- synchronized int createDocument(int deviceId, MtpObjectInfo objectInfo,
+ int createDocument(int deviceId, MtpObjectInfo objectInfo,
ParcelFileDescriptor source) throws IOException {
final MtpDevice device = getDevice(deviceId);
- final MtpObjectInfo sendObjectInfoResult = device.sendObjectInfo(objectInfo);
- if (sendObjectInfoResult == null) {
- throw new IOException("Failed to create a document");
- }
- if (objectInfo.getFormat() != MtpConstants.FORMAT_ASSOCIATION) {
- if (!device.sendObject(sendObjectInfoResult.getObjectHandle(),
- sendObjectInfoResult.getCompressedSize(), source)) {
- throw new IOException("Failed to send contents of a document");
+ synchronized (device) {
+ final MtpObjectInfo sendObjectInfoResult = device.sendObjectInfo(objectInfo);
+ if (sendObjectInfoResult == null) {
+ throw new IOException("Failed to create a document");
+ }
+ if (objectInfo.getFormat() != MtpConstants.FORMAT_ASSOCIATION) {
+ if (!device.sendObject(sendObjectInfoResult.getObjectHandle(),
+ sendObjectInfoResult.getCompressedSize(), source)) {
+ throw new IOException("Failed to send contents of a document");
+ }
}
+ return sendObjectInfoResult.getObjectHandle();
}
- return sendObjectInfoResult.getObjectHandle();
}
- synchronized int getParent(int deviceId, int objectHandle) throws IOException {
+ int getParent(int deviceId, int objectHandle) throws IOException {
final MtpDevice device = getDevice(deviceId);
- final int result = (int) device.getParent(objectHandle);
- if (result < 0) {
- throw new FileNotFoundException("Not found parent object");
+ synchronized (device) {
+ final int result = (int) device.getParent(objectHandle);
+ if (result < 0) {
+ throw new FileNotFoundException("Not found parent object");
+ }
+ return result;
}
- return result;
}
- synchronized void importFile(int deviceId, int objectHandle, ParcelFileDescriptor target)
+ void importFile(int deviceId, int objectHandle, ParcelFileDescriptor target)
throws IOException {
final MtpDevice device = getDevice(deviceId);
- device.importFile(objectHandle, target);
+ synchronized (device) {
+ device.importFile(objectHandle, target);
+ }
}
private MtpDevice getDevice(int deviceId) throws IOException {
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java
index cd38f1e852b5..affaebd05c16 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java
@@ -33,7 +33,7 @@ class PipeManager {
final ExecutorService mExecutor;
PipeManager() {
- this(Executors.newCachedThreadPool());
+ this(Executors.newSingleThreadExecutor());
}
PipeManager(ExecutorService executor) {
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
index 9b316be48a15..4b3a5cd061bf 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
@@ -39,7 +39,7 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
private TestMtpManager mMtpManager;
@Override
- public void setUp() {
+ public void setUp() throws IOException {
mResolver = new TestContentResolver();
mMtpManager = new TestMtpManager(getContext());
mProvider = new MtpDocumentsProvider();
@@ -207,6 +207,8 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
}
public void testQueryDocument() throws IOException {
+ mMtpManager.addValidDevice(0);
+ mProvider.openDevice(0);
mMtpManager.setObjectInfo(0, new MtpObjectInfo.Builder()
.setObjectHandle(2)
.setFormat(MtpConstants.FORMAT_EXIF_JPEG)
@@ -232,6 +234,8 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
}
public void testQueryDocument_directory() throws IOException {
+ mMtpManager.addValidDevice(0);
+ mProvider.openDevice(0);
mMtpManager.setObjectInfo(0, new MtpObjectInfo.Builder()
.setObjectHandle(2)
.setFormat(MtpConstants.FORMAT_ASSOCIATION)
@@ -255,6 +259,8 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
}
public void testQueryDocument_forRoot() throws IOException {
+ mMtpManager.addValidDevice(0);
+ mProvider.openDevice(0);
mMtpManager.setRoots(0, new MtpRoot[] {
new MtpRoot(
0 /* deviceId */,
@@ -277,6 +283,8 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
}
public void testQueryChildDocuments() throws Exception {
+ mMtpManager.addValidDevice(0);
+ mProvider.openDevice(0);
mMtpManager.setObjectHandles(0, 0, -1, new int[] { 1 });
mMtpManager.setObjectInfo(0, new MtpObjectInfo.Builder()
@@ -303,6 +311,8 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
}
public void testQueryChildDocuments_cursorError() throws Exception {
+ mMtpManager.addValidDevice(0);
+ mProvider.openDevice(0);
try {
mProvider.queryChildDocuments("0_0_0", null, null);
fail();
@@ -312,6 +322,8 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
}
public void testQueryChildDocuments_documentError() throws Exception {
+ mMtpManager.addValidDevice(0);
+ mProvider.openDevice(0);
mMtpManager.setObjectHandles(0, 0, -1, new int[] { 1 });
try {
mProvider.queryChildDocuments("0_0_0", null, null);
@@ -321,7 +333,9 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
}
}
- public void testDeleteDocument() throws FileNotFoundException {
+ public void testDeleteDocument() throws IOException {
+ mMtpManager.addValidDevice(0);
+ mProvider.openDevice(0);
mMtpManager.setObjectInfo(0, new MtpObjectInfo.Builder()
.setObjectHandle(1)
.setParent(2)
@@ -332,7 +346,9 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
MtpDocumentsProvider.AUTHORITY, "0_0_2")));
}
- public void testDeleteDocument_error() {
+ public void testDeleteDocument_error() throws IOException {
+ mMtpManager.addValidDevice(0);
+ mProvider.openDevice(0);
mMtpManager.setObjectInfo(0, new MtpObjectInfo.Builder()
.setObjectHandle(2)
.build());
diff --git a/packages/PrintSpooler/jni/com_android_printspooler_util_BitmapSerializeUtils.cpp b/packages/PrintSpooler/jni/com_android_printspooler_util_BitmapSerializeUtils.cpp
index b5d91385abe5..1530a02c22fe 100644
--- a/packages/PrintSpooler/jni/com_android_printspooler_util_BitmapSerializeUtils.cpp
+++ b/packages/PrintSpooler/jni/com_android_printspooler_util_BitmapSerializeUtils.cpp
@@ -166,7 +166,7 @@ static void writeBitmapPixels(JNIEnv* env, jclass /* clazz */, jobject jbitmap,
}
}
-static JNINativeMethod sMethods[] = {
+static const JNINativeMethod sMethods[] = {
{"nativeReadBitmapPixels", "(Landroid/graphics/Bitmap;I)V", (void *) readBitmapPixels},
{"nativeWriteBitmapPixels", "(Landroid/graphics/Bitmap;I)V", (void *) writeBitmapPixels},
};
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/SettingsLib/src/com/android/settingslib/TetherUtil.java b/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java
index f52d75502e7d..66233b82b8dc 100644
--- a/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java
+++ b/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java
@@ -25,6 +25,7 @@ import android.net.wifi.WifiManager;
import android.os.SystemProperties;
import android.os.UserManager;
import android.provider.Settings;
+import android.telephony.CarrierConfigManager;
public class TetherUtil {
@@ -62,6 +63,13 @@ public class TetherUtil {
return wifiManager.getWifiApState() == WifiManager.WIFI_AP_STATE_ENABLED;
}
+ private static boolean isEntitlementCheckRequired(Context context) {
+ final CarrierConfigManager configManager = (CarrierConfigManager) context
+ .getSystemService(Context.CARRIER_CONFIG_SERVICE);
+ return configManager.getConfig().getBoolean(CarrierConfigManager
+ .KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL);
+ }
+
public static boolean isProvisioningNeeded(Context context) {
// Keep in sync with other usage of config_mobile_hotspot_provision_app.
// ConnectivityManager#enforceTetherChangePermission
@@ -71,6 +79,10 @@ public class TetherUtil {
|| provisionApp == null) {
return false;
}
+ // Check carrier config for entitlement checks
+ if (isEntitlementCheckRequired(context) == false) {
+ return false;
+ }
return (provisionApp.length == 2);
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index 1d71346b575b..e12e3a571880 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -166,7 +166,7 @@ public class SettingsHelper {
.putExtra(Intent.EXTRA_SETTING_NAME, name)
.putExtra(Intent.EXTRA_SETTING_NEW_VALUE, value)
.putExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE, oldValue);
- context.sendBroadcastAsUser(intent, UserHandle.OWNER, null);
+ context.sendBroadcastAsUser(intent, UserHandle.SYSTEM, null);
}
}
}
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index e4fc0751fa46..8fc7ad089427 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -205,7 +205,8 @@
android:stateNotNeeded="true"
android:resumeWhilePausing="true"
android:screenOrientation="behind"
- android:theme="@style/config_recents_activity_theme">
+ android:resizeableActivity="true"
+ android:theme="@style/RecentsTheme.Wallpaper">
<intent-filter>
<action android:name="com.android.systemui.recents.TOGGLE_RECENTS" />
</intent-filter>
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/layout/recents.xml b/packages/SystemUI/res/layout/recents.xml
index 8140dd68710e..064d2258150f 100644
--- a/packages/SystemUI/res/layout/recents.xml
+++ b/packages/SystemUI/res/layout/recents.xml
@@ -39,12 +39,6 @@
android:layout_width="match_parent"
android:layout_height="match_parent" />
- <!-- Debug Overlay View -->
- <ViewStub android:id="@+id/debug_overlay_stub"
- android:layout="@layout/recents_debug_overlay"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
-
<!-- Nav Bar Scrim View -->
<ImageView
android:id="@+id/nav_bar_scrim"
diff --git a/packages/SystemUI/res/layout/recents_debug_overlay.xml b/packages/SystemUI/res/layout/recents_debug_overlay.xml
deleted file mode 100644
index d23495e6043e..000000000000
--- a/packages/SystemUI/res/layout/recents_debug_overlay.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<com.android.systemui.recents.views.DebugOverlayView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:focusable="false">
- <SeekBar
- android:id="@+id/debug_seek_bar_1"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="top"
- android:layout_marginTop="25dp" />
- <SeekBar
- android:id="@+id/debug_seek_bar_2"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="top"
- android:layout_marginTop="50dp" />
-</com.android.systemui.recents.views.DebugOverlayView>
-
-
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index cc37162f99c1..8b2951a80a30 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -406,7 +406,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 +428,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-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 6f491874e6a8..91d975bf08f7 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>
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-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 7593f46e6c70..147cbe4a5c80 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>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 8ee5f078a806..0d0663675b02 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -354,7 +354,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-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index a73f4c1d9fc6..a034f4f32c3a 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -330,7 +330,7 @@
<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 +364,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-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..2893b999997f 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -19,25 +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>
diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
index 3a62ad94f2c7..81ca86bcb9ef 100644
--- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
@@ -17,8 +17,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>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 1af4ab1f4b15..6deb818ade04 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>
diff --git a/packages/SystemUI/res/values-sw720dp/config.xml b/packages/SystemUI/res/values-sw720dp/config.xml
index fbeadcd56da7..1efae42eac2b 100644
--- a/packages/SystemUI/res/values-sw720dp/config.xml
+++ b/packages/SystemUI/res/values-sw720dp/config.xml
@@ -22,20 +22,6 @@
<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>
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-uz-rUZ/strings.xml b/packages/SystemUI/res/values-uz-rUZ/strings.xml
index 04ec78b07526..9f9fe5f6e427 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>
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..f28c9d3efc14 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>
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/RecentsComponent.java b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
index dd93389880b0..1d0bfe7dc6f1 100644
--- a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
@@ -20,10 +20,6 @@ import android.view.Display;
import android.view.View;
public interface RecentsComponent {
- public interface Callbacks {
- public void onVisibilityChanged(boolean visible);
- }
-
void showRecents(boolean triggeredFromAltTab, View statusBarView);
void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey);
void toggleRecents(Display display, int layoutDirection, View statusBarView);
@@ -31,5 +27,4 @@ public interface RecentsComponent {
void cancelPreloadingRecents();
void showNextAffiliatedTask();
void showPrevAffiliatedTask();
- void setCallback(Callbacks cb);
}
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/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 33bd726c8d4e..5bf251b57af1 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -22,7 +22,9 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Configuration;
+import android.os.Process;
import android.os.SystemProperties;
+import android.os.UserHandle;
import android.util.Log;
import java.util.HashMap;
@@ -51,12 +53,20 @@ public class SystemUIApplication extends Application {
};
/**
+ * The classes of the stuff to start for each user. This is a subset of the services listed
+ * above.
+ */
+ private final Class<?>[] SERVICES_PER_USER = new Class[] {
+ com.android.systemui.recents.Recents.class
+ };
+
+ /**
* Hold a reference on the stuff we start.
*/
private final SystemUI[] mServices = new SystemUI[SERVICES.length];
private boolean mServicesStarted;
private boolean mBootCompleted;
- private final Map<Class<?>, Object> mComponents = new HashMap<Class<?>, Object>();
+ private final Map<Class<?>, Object> mComponents = new HashMap<>();
@Override
public void onCreate() {
@@ -66,24 +76,32 @@ public class SystemUIApplication extends Application {
// the theme set there.
setTheme(R.style.systemui_theme);
- IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
- filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
- registerReceiver(new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (mBootCompleted) return;
-
- if (DEBUG) Log.v(TAG, "BOOT_COMPLETED received");
- unregisterReceiver(this);
- mBootCompleted = true;
- if (mServicesStarted) {
- final int N = mServices.length;
- for (int i = 0; i < N; i++) {
- mServices[i].onBootCompleted();
+ if (Process.myUserHandle().equals(UserHandle.SYSTEM)) {
+ IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
+ filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
+ registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (mBootCompleted) return;
+
+ if (DEBUG) Log.v(TAG, "BOOT_COMPLETED received");
+ unregisterReceiver(this);
+ mBootCompleted = true;
+ if (mServicesStarted) {
+ final int N = mServices.length;
+ for (int i = 0; i < N; i++) {
+ mServices[i].onBootCompleted();
+ }
}
}
- }
- }, filter);
+ }, filter);
+ } else {
+ // For a secondary user, boot-completed will never be called because it has already
+ // been broadcasted on startup for the primary SystemUI process. Instead, for
+ // components which require the SystemUI component to be initialized per-user, we
+ // start those components now for the current non-system user.
+ startServicesIfNeeded(SERVICES_PER_USER);
+ }
}
/**
@@ -94,6 +112,10 @@ public class SystemUIApplication extends Application {
* <p>This method must only be called from the main thread.</p>
*/
public void startServicesIfNeeded() {
+ startServicesIfNeeded(SERVICES);
+ }
+
+ private void startServicesIfNeeded(Class<?>[] services) {
if (mServicesStarted) {
return;
}
@@ -107,13 +129,14 @@ public class SystemUIApplication extends Application {
}
}
- Log.v(TAG, "Starting SystemUI services.");
- final int N = SERVICES.length;
+ Log.v(TAG, "Starting SystemUI services for user " +
+ Process.myUserHandle().getIdentifier() + ".");
+ final int N = services.length;
for (int i=0; i<N; i++) {
- Class<?> cl = SERVICES[i];
+ Class<?> cl = services[i];
if (DEBUG) Log.d(TAG, "loading: " + cl);
try {
- mServices[i] = (SystemUI)cl.newInstance();
+ mServices[i] = (SystemUI) cl.newInstance();
} catch (IllegalAccessException ex) {
throw new RuntimeException(ex);
} catch (InstantiationException ex) {
@@ -136,7 +159,9 @@ public class SystemUIApplication extends Application {
if (mServicesStarted) {
int len = mServices.length;
for (int i = 0; i < len; i++) {
- mServices[i].onConfigurationChanged(newConfig);
+ if (mServices[i] != null) {
+ mServices[i].onConfigurationChanged(newConfig);
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/analytics/LockedPhoneAnalytics.java b/packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java
index e458862295e1..91f652056326 100644
--- a/packages/SystemUI/src/com/android/systemui/analytics/LockedPhoneAnalytics.java
+++ b/packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java
@@ -21,7 +21,6 @@ import android.database.ContentObserver;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
-import android.hardware.SensorManager;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Handler;
@@ -30,8 +29,6 @@ import android.provider.Settings;
import android.util.Log;
import android.view.MotionEvent;
-import com.android.systemui.statusbar.StatusBarState;
-
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -47,94 +44,70 @@ import static com.android.systemui.statusbar.phone.TouchAnalyticsProto.Session.P
* A session starts when the screen is turned on.
* A session ends when the screen is turned off or user unlocks the phone.
*/
-public class LockedPhoneAnalytics implements SensorEventListener {
- private static final String TAG = "LockedPhoneAnalytics";
- private static final String ANALYTICS_ENABLE = "locked_phone_analytics_enable";
- private static final String ENFORCE_BOUNCER = "locked_phone_analytics_enforce_bouncer";
- private static final String COLLECT_BAD_TOCUHES = "locked_phone_analytics_collect_bad_touches";
+public class DataCollector implements SensorEventListener {
+ private static final String TAG = "DataCollector";
+ private static final String COLLECTOR_ENABLE = "data_collector_enable";
+ private static final String COLLECT_BAD_TOUCHES = "data_collector_collect_bad_touches";
private static final long TIMEOUT_MILLIS = 11000; // 11 seconds.
public static final boolean DEBUG = false;
- private static final int[] SENSORS = new int[] {
- Sensor.TYPE_ACCELEROMETER,
- Sensor.TYPE_GYROSCOPE,
- Sensor.TYPE_PROXIMITY,
- Sensor.TYPE_LIGHT,
- Sensor.TYPE_ROTATION_VECTOR,
- };
-
private final Handler mHandler = new Handler();
- protected final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
- @Override
- public void onChange(boolean selfChange) {
- updateConfiguration();
- }
- };
-
- private final SensorManager mSensorManager;
private final Context mContext;
// Err on the side of caution, so logging is not started after a crash even tough the screen
// is off.
private SensorLoggerSession mCurrentSession = null;
- private boolean mEnableAnalytics = false;
- private boolean mEnforceBouncer = false;
+ private boolean mEnableCollector = false;
private boolean mTimeoutActive = false;
private boolean mCollectBadTouches = false;
- private boolean mBouncerOn = false;
private boolean mCornerSwiping = false;
private boolean mTrackingStarted = false;
- private int mState = StatusBarState.SHADE;
+ private static DataCollector sInstance = null;
- private static LockedPhoneAnalytics sInstance = null;
+ protected final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
+ @Override
+ public void onChange(boolean selfChange) {
+ updateConfiguration();
+ }
+ };
- private LockedPhoneAnalytics(Context context) {
- mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
+ private DataCollector(Context context) {
mContext = context;
mContext.getContentResolver().registerContentObserver(
- Settings.Secure.getUriFor(ANALYTICS_ENABLE), false,
+ Settings.Secure.getUriFor(COLLECTOR_ENABLE), false,
mSettingsObserver,
UserHandle.USER_ALL);
mContext.getContentResolver().registerContentObserver(
- Settings.Secure.getUriFor(ENFORCE_BOUNCER), false,
- mSettingsObserver,
- UserHandle.USER_ALL);
-
- mContext.getContentResolver().registerContentObserver(
- Settings.Secure.getUriFor(COLLECT_BAD_TOCUHES), false,
+ Settings.Secure.getUriFor(COLLECT_BAD_TOUCHES), false,
mSettingsObserver,
UserHandle.USER_ALL);
updateConfiguration();
}
- public static LockedPhoneAnalytics getInstance(Context context) {
+ public static DataCollector getInstance(Context context) {
if (sInstance == null) {
- sInstance = new LockedPhoneAnalytics(context);
+ sInstance = new DataCollector(context);
}
return sInstance;
}
private void updateConfiguration() {
- mEnableAnalytics = Build.IS_DEBUGGABLE && 0 != Settings.Secure.getInt(
+ mEnableCollector = Build.IS_DEBUGGABLE && 0 != Settings.Secure.getInt(
mContext.getContentResolver(),
- ANALYTICS_ENABLE, 0);
- mEnforceBouncer = mEnableAnalytics && 0 != Settings.Secure.getInt(
+ COLLECTOR_ENABLE, 0);
+ mCollectBadTouches = mEnableCollector && 0 != Settings.Secure.getInt(
mContext.getContentResolver(),
- ENFORCE_BOUNCER, 0);
- mCollectBadTouches = mEnableAnalytics && 0 != Settings.Secure.getInt(
- mContext.getContentResolver(),
- COLLECT_BAD_TOCUHES, 0);
+ COLLECT_BAD_TOUCHES, 0);
}
private boolean sessionEntrypoint() {
- if ((mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED)
- && mEnableAnalytics && mCurrentSession == null) {
+ if (mEnableCollector && mCurrentSession == null) {
onSessionStart();
return true;
}
@@ -142,22 +115,15 @@ public class LockedPhoneAnalytics implements SensorEventListener {
}
private void sessionExitpoint(int result) {
- if (mEnableAnalytics && mCurrentSession != null) {
+ if (mEnableCollector && mCurrentSession != null) {
onSessionEnd(result);
}
}
private void onSessionStart() {
- mBouncerOn = false;
mCornerSwiping = false;
mTrackingStarted = false;
mCurrentSession = new SensorLoggerSession(System.currentTimeMillis(), System.nanoTime());
- for (int sensorType : SENSORS) {
- Sensor s = mSensorManager.getDefaultSensor(sensorType);
- if (s != null) {
- mSensorManager.registerListener(this, s, SensorManager.SENSOR_DELAY_GAME);
- }
- }
}
private void onSessionEnd(int result) {
@@ -196,10 +162,9 @@ public class LockedPhoneAnalytics implements SensorEventListener {
});
}
-
@Override
public synchronized void onSensorChanged(SensorEvent event) {
- if (mEnableAnalytics && mCurrentSession != null) {
+ if (mEnableCollector && mCurrentSession != null) {
mCurrentSession.addSensorEvent(event, System.nanoTime());
enforceTimeout();
}
@@ -221,18 +186,14 @@ public class LockedPhoneAnalytics implements SensorEventListener {
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
- public boolean shouldEnforceBouncer() {
- return mEnforceBouncer;
+ public boolean isEnabled() {
+ return mEnableCollector;
}
- public void setStatusBarState(int state) {
- mState = state;
- }
-
- public void onScreenOn() {
+ public void onScreenTurningOn() {
if (sessionEntrypoint()) {
if (DEBUG) {
- Log.d(TAG, "onScreenOn");
+ Log.d(TAG, "onScreenTurningOn");
}
addEvent(PhoneEvent.ON_SCREEN_ON);
}
@@ -264,23 +225,17 @@ public class LockedPhoneAnalytics implements SensorEventListener {
}
public void onBouncerShown() {
- if (!mBouncerOn) {
- if (DEBUG) {
- Log.d(TAG, "onBouncerShown");
- }
- mBouncerOn = true;
- addEvent(PhoneEvent.ON_BOUNCER_SHOWN);
+ if (DEBUG) {
+ Log.d(TAG, "onBouncerShown");
}
+ addEvent(PhoneEvent.ON_BOUNCER_SHOWN);
}
public void onBouncerHidden() {
- if (mBouncerOn) {
- if (DEBUG) {
- Log.d(TAG, "onBouncerHidden");
- }
- mBouncerOn = false;
- addEvent(PhoneEvent.ON_BOUNCER_HIDDEN);
+ if (DEBUG) {
+ Log.d(TAG, "onBouncerHidden");
}
+ addEvent(PhoneEvent.ON_BOUNCER_HIDDEN);
}
public void onQsDown() {
@@ -433,20 +388,20 @@ public class LockedPhoneAnalytics implements SensorEventListener {
addEvent(PhoneEvent.ON_LEFT_AFFORDANCE_HINT_STARTED);
}
- public void onTouchEvent(MotionEvent ev, int width, int height) {
- if (!mBouncerOn && mCurrentSession != null) {
+ public void onTouchEvent(MotionEvent event, int width, int height) {
+ if (mCurrentSession != null) {
if (DEBUG) {
Log.v(TAG, "onTouchEvent(ev.action="
- + MotionEvent.actionToString(ev.getAction()) + ")");
+ + MotionEvent.actionToString(event.getAction()) + ")");
}
- mCurrentSession.addMotionEvent(ev);
+ mCurrentSession.addMotionEvent(event);
mCurrentSession.setTouchArea(width, height);
enforceTimeout();
}
}
private void addEvent(int eventType) {
- if (mEnableAnalytics && mCurrentSession != null) {
+ if (mEnableCollector && mCurrentSession != null) {
mCurrentSession.addPhoneEvent(eventType, System.nanoTime());
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/analytics/SensorLoggerSession.java b/packages/SystemUI/src/com/android/systemui/analytics/SensorLoggerSession.java
index 09383f6aa8d1..0e280028b6f0 100644
--- a/packages/SystemUI/src/com/android/systemui/analytics/SensorLoggerSession.java
+++ b/packages/SystemUI/src/com/android/systemui/analytics/SensorLoggerSession.java
@@ -57,7 +57,7 @@ public class SensorLoggerSession {
mResult = result;
mEndTimestampMillis = endTimestampMillis;
- if (LockedPhoneAnalytics.DEBUG) {
+ if (DataCollector.DEBUG) {
Log.d(TAG, "Ending session result=" + result + " it lasted for " +
(float) (mEndTimestampMillis - mStartTimestampMillis) / 1000f + "s");
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/AccelerationClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/AccelerationClassifier.java
new file mode 100644
index 000000000000..86bea873b737
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/AccelerationClassifier.java
@@ -0,0 +1,94 @@
+/*
+ * 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;
+
+import android.view.MotionEvent;
+
+import java.util.HashMap;
+
+/**
+ * A classifier which looks at the speed and distance between successive points of a Stroke.
+ * It looks at two consecutive speeds between two points and calculates the ratio between them.
+ * The final result is the maximum of these values. It does the same for distances. If some speed
+ * or distance is equal to zero then the ratio between this and the next part is not calculated. To
+ * the duration of each part there is added one nanosecond so that it is always possible to
+ * calculate the speed of a part.
+ */
+public class AccelerationClassifier extends StrokeClassifier {
+ private final HashMap<Stroke, Data> mStrokeMap = new HashMap<>();
+
+ public AccelerationClassifier(ClassifierData classifierData) {
+ mClassifierData = classifierData;
+ }
+
+ @Override
+ public void onTouchEvent(MotionEvent event) {
+ int action = event.getActionMasked();
+
+ if (action == MotionEvent.ACTION_DOWN) {
+ mStrokeMap.clear();
+ }
+
+ for (int i = 0; i < event.getPointerCount(); i++) {
+ Stroke stroke = mClassifierData.getStroke(event.getPointerId(i));
+ Point point = stroke.getPoints().get(stroke.getPoints().size() - 1);
+ if (mStrokeMap.get(stroke) == null) {
+ mStrokeMap.put(stroke, new Data(point));
+ } else {
+ mStrokeMap.get(stroke).addPoint(point);
+ }
+ }
+ }
+
+ @Override
+ public float getFalseTouchEvaluation(int type, Stroke stroke) {
+ Data data = mStrokeMap.get(stroke);
+ return SpeedRatioEvaluator.evaluate(data.maxSpeedRatio)
+ + DistanceRatioEvaluator.evaluate(data.maxDistanceRatio);
+ }
+
+ private static class Data {
+ public Point previousPoint;
+ public float previousSpeed;
+ public float previousDistance;
+ public float maxSpeedRatio;
+ public float maxDistanceRatio;
+
+ public Data(Point point) {
+ previousPoint = point;
+ previousSpeed = previousDistance = 0.0f;
+ maxDistanceRatio = maxSpeedRatio = 0.0f;
+ }
+
+ public void addPoint(Point point) {
+ float distance = previousPoint.dist(point);
+ float duration = (float) (point.timeOffsetNano - previousPoint.timeOffsetNano + 1);
+ float speed = distance / duration;
+ if (previousDistance != 0.0f) {
+ maxDistanceRatio = Math.max(maxDistanceRatio, distance / previousDistance);
+ }
+
+ if (previousSpeed != 0.0f) {
+ maxSpeedRatio = Math.max(maxSpeedRatio, speed / previousSpeed);
+ }
+
+ previousDistance = distance;
+ previousSpeed = speed;
+ previousPoint = point;
+ }
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceClassifier.java
new file mode 100644
index 000000000000..c74339b9082b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceClassifier.java
@@ -0,0 +1,140 @@
+/*
+ * 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;
+
+import android.view.MotionEvent;
+
+import java.lang.Math;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * A classifier which calculates the variance of differences between successive angles in a stroke.
+ * For each stroke it keeps its last three points. If some successive points are the same, it
+ * ignores the repetitions. If a new point is added, the classifier calculates the angle between
+ * the last three points. After that, it calculates the difference between this angle and the
+ * 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.
+ */
+public class AnglesVarianceClassifier extends StrokeClassifier {
+ private HashMap<Stroke, Data> mStrokeMap = new HashMap<>();
+
+ public AnglesVarianceClassifier(ClassifierData classifierData) {
+ mClassifierData = classifierData;
+ }
+
+ @Override
+ public void onTouchEvent(MotionEvent event) {
+ int action = event.getActionMasked();
+
+ if (action == MotionEvent.ACTION_DOWN) {
+ mStrokeMap.clear();
+ }
+
+ for (int i = 0; i < event.getPointerCount(); i++) {
+ Stroke stroke = mClassifierData.getStroke(event.getPointerId(i));
+
+ if (mStrokeMap.get(stroke) == null) {
+ mStrokeMap.put(stroke, new Data());
+ }
+ mStrokeMap.get(stroke).addPoint(stroke.getPoints().get(stroke.getPoints().size() - 1));
+ }
+ }
+
+ @Override
+ public float getFalseTouchEvaluation(int type, Stroke stroke) {
+ return AnglesVarianceEvaluator.evaluate(mStrokeMap.get(stroke).getAnglesVariance());
+ }
+
+ private static class Data {
+ private List<Point> mLastThreePoints = new ArrayList<>();
+ private float mFirstAngleVariance;
+ private float mPreviousAngle;
+ private float mBiggestAngle;
+ private float mSumSquares;
+ private float mSecondSumSquares;
+ private float mSum;
+ private float mSecondSum;
+ private float mCount;
+ private float mSecondCount;
+
+ public Data() {
+ mFirstAngleVariance = 0.0f;
+ mPreviousAngle = (float) Math.PI;
+ mBiggestAngle = 0.0f;
+ mSumSquares = mSecondSumSquares = 0.0f;
+ mSum = mSecondSum = 0.0f;
+ mCount = mSecondCount = 1.0f;
+ }
+
+ public void addPoint(Point point) {
+ // Checking if the added point is different than the previously added point
+ // Repetitions are being ignored so that proper angles are calculated.
+ if (mLastThreePoints.isEmpty()
+ || !mLastThreePoints.get(mLastThreePoints.size() - 1).equals(point)) {
+ mLastThreePoints.add(point);
+ if (mLastThreePoints.size() == 4) {
+ mLastThreePoints.remove(0);
+
+ float angle = mLastThreePoints.get(1).getAngle(mLastThreePoints.get(0),
+ mLastThreePoints.get(2));
+
+ float difference = angle - mPreviousAngle;
+
+ // If this is the biggest angle of the stroke so then we save the value of
+ // the angle variance so far and start to count the values for the angle
+ // variance of the second part.
+ if (mBiggestAngle < angle) {
+ mBiggestAngle = angle;
+ mFirstAngleVariance = getAnglesVariance(mSumSquares, mSum, mCount);
+ mSecondSumSquares = 0.0f;
+ mSecondSum = 0.0f;
+ mSecondCount = 1.0f;
+ } else {
+ mSecondSum += difference;
+ mSecondSumSquares += difference * difference;
+ mSecondCount += 1.0;
+ }
+
+ mSum += difference;
+ mSumSquares += difference * difference;
+ mCount += 1.0;
+ mPreviousAngle = angle;
+ }
+ }
+ }
+
+ public float getAnglesVariance(float sumSquares, float sum, float count) {
+ return sumSquares / count - (sum / count) * (sum / count);
+ }
+
+ public float getAnglesVariance() {
+ return Math.min(getAnglesVariance(mSumSquares, mSum, mCount),
+ mFirstAngleVariance + getAnglesVariance(mSecondSumSquares, mSecondSum,
+ mSecondCount));
+ }
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceEvaluator.java
new file mode 100644
index 000000000000..99cc1a6d14fe
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceEvaluator.java
@@ -0,0 +1,30 @@
+/*
+ * 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 AnglesVarianceEvaluator {
+ public static float evaluate(float value) {
+ float evaluation = 0.0f;
+ if (value > 0.05) evaluation++;
+ if (value > 0.10) evaluation++;
+ if (value > 0.20) evaluation++;
+ if (value > 0.40) evaluation++;
+ if (value > 0.80) evaluation++;
+ if (value > 1.50) evaluation++;
+ return evaluation;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java b/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java
new file mode 100644
index 000000000000..89d20defc7db
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java
@@ -0,0 +1,51 @@
+/*
+ * 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;
+
+import android.hardware.SensorEvent;
+import android.view.MotionEvent;
+
+/**
+ * An abstract class for classifiers for touch and sensor events.
+ */
+public abstract class Classifier {
+ public static final int QUICK_SETTINGS = 0;
+ public static final int NOTIFICATION_DISMISS = 1;
+ public static final int NOTIFICATION_DRAG_DOWN = 2;
+ public static final int NOTIFICATION_DOUBLE_TAP = 3;
+ public static final int UNLOCK = 4;
+ public static final int LEFT_AFFORDANCE = 5;
+ public static final int RIGHT_AFFORDANCE = 6;
+ public static final int GENERIC = 7;
+
+ /**
+ * Contains all the information about touch events from which the classifier can query
+ */
+ protected ClassifierData mClassifierData;
+
+ /**
+ * Informs the classifier that a new touch event has occurred
+ */
+ public void onTouchEvent(MotionEvent event) {
+ }
+
+ /**
+ * Informs the classifier that a sensor change occurred
+ */
+ public void onSensorChanged(SensorEvent event) {
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/ClassifierData.java b/packages/SystemUI/src/com/android/systemui/classifier/ClassifierData.java
new file mode 100644
index 000000000000..c83c74f69f90
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/ClassifierData.java
@@ -0,0 +1,85 @@
+/*
+ * 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;
+
+import android.util.SparseArray;
+import android.view.MotionEvent;
+
+import java.util.ArrayList;
+
+/**
+ * Contains data which is used to classify interaction sequences on the lockscreen. It does, for
+ * example, provide information on the current touch state.
+ */
+public class ClassifierData {
+ private SparseArray<Stroke> mCurrentStrokes = new SparseArray<>();
+ private ArrayList<Stroke> mEndingStrokes = new ArrayList<>();
+ private final float mDpi;
+
+ public ClassifierData(float dpi) {
+ mDpi = dpi;
+ }
+
+ public void update(MotionEvent event) {
+ mEndingStrokes.clear();
+ int action = event.getActionMasked();
+ if (action == MotionEvent.ACTION_DOWN) {
+ mCurrentStrokes.clear();
+ }
+
+ 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(), mDpi));
+ }
+ mCurrentStrokes.get(id).addPoint(event.getX(i), event.getY(i),
+ event.getEventTimeNano());
+
+ if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL
+ || (action == MotionEvent.ACTION_POINTER_UP && i == event.getActionIndex())) {
+ mEndingStrokes.add(getStroke(id));
+ }
+ }
+ }
+
+ public void cleanUp(MotionEvent event) {
+ mEndingStrokes.clear();
+ int action = event.getActionMasked();
+ for (int i = 0; i < event.getPointerCount(); i++) {
+ int id = event.getPointerId(i);
+ if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL
+ || (action == MotionEvent.ACTION_POINTER_UP && i == event.getActionIndex())) {
+ mCurrentStrokes.remove(id);
+ }
+ }
+ }
+
+ /**
+ * @return the list of Strokes which are ending in the recently added MotionEvent
+ */
+ public ArrayList<Stroke> getEndingStrokes() {
+ return mEndingStrokes;
+ }
+
+ /**
+ * @param id the id from MotionEvent
+ * @return the Stroke assigned to the id
+ */
+ public Stroke getStroke(int id) {
+ return mCurrentStrokes.get(id);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DistanceRatioEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/DistanceRatioEvaluator.java
new file mode 100644
index 000000000000..8acb009a230f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/DistanceRatioEvaluator.java
@@ -0,0 +1,29 @@
+/*
+ * 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 DistanceRatioEvaluator {
+ public static float evaluate(float value) {
+ float evaluation = 0.0f;
+ if (value <= 1.0) evaluation++;
+ if (value <= 0.5) evaluation++;
+ if (value > 4.0) evaluation++;
+ if (value > 7.0) evaluation++;
+ if (value > 14.0) evaluation++;
+ return evaluation;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DurationCountClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/DurationCountClassifier.java
new file mode 100644
index 000000000000..892469428f4a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/DurationCountClassifier.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 com.android.systemui.classifier;
+
+/**
+ * A classifier which looks at the ratio between the duration of the stroke and its number of
+ * points.
+ */
+public class DurationCountClassifier extends StrokeClassifier {
+ public DurationCountClassifier(ClassifierData classifierData) {
+ }
+
+ @Override
+ public float getFalseTouchEvaluation(int type, Stroke stroke) {
+ return DurationCountEvaluator.evaluate(stroke.getDurationSeconds() / stroke.getCount());
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DurationCountEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/DurationCountEvaluator.java
new file mode 100644
index 000000000000..5395983968f7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/DurationCountEvaluator.java
@@ -0,0 +1,30 @@
+/*
+ * 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 DurationCountEvaluator {
+ public static float evaluate(float value) {
+ float evaluation = 0.0f;
+ if (value < 0.0105) evaluation++;
+ if (value < 0.00909) evaluation++;
+ if (value < 0.00667) evaluation++;
+ if (value > 0.0333) evaluation++;
+ if (value > 0.0500) evaluation++;
+ return evaluation;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/EndPointLengthClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/EndPointLengthClassifier.java
new file mode 100644
index 000000000000..78bc0ddf1942
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/EndPointLengthClassifier.java
@@ -0,0 +1,30 @@
+/*
+ * 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 distance between the first and the last point from the stroke.
+ */
+public class EndPointLengthClassifier extends StrokeClassifier {
+ public EndPointLengthClassifier(ClassifierData classifierData) {
+ }
+
+ @Override
+ public float getFalseTouchEvaluation(int type, Stroke stroke) {
+ return EndPointLengthEvaluator.evaluate(stroke.getEndPointLength());
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/EndPointLengthEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/EndPointLengthEvaluator.java
new file mode 100644
index 000000000000..bb2f1c4e355d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/EndPointLengthEvaluator.java
@@ -0,0 +1,30 @@
+/*
+ * 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 EndPointLengthEvaluator {
+ public static float evaluate(float value) {
+ float evaluation = 0.0f;
+ if (value < 0.05) evaluation += 2.0;
+ if (value < 0.1) evaluation += 2.0;
+ if (value < 0.2) evaluation += 2.0;
+ if (value < 0.3) evaluation += 2.0;
+ if (value < 0.4) evaluation += 2.0;
+ if (value < 0.5) evaluation += 2.0;
+ return evaluation;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/EndPointRatioClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/EndPointRatioClassifier.java
new file mode 100644
index 000000000000..c125e0093db5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/EndPointRatioClassifier.java
@@ -0,0 +1,36 @@
+/*
+ * 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 ratio between the total length covered by the stroke and the
+ * distance between the first and last point from this stroke.
+ */
+public class EndPointRatioClassifier extends StrokeClassifier {
+ public EndPointRatioClassifier(ClassifierData classifierData) {
+ mClassifierData = classifierData;
+ }
+
+ @Override
+ public float getFalseTouchEvaluation(int type, Stroke stroke) {
+ if (stroke.getTotalLength() == 0.0f) {
+ return 1.0f;
+ }
+ return EndPointRatioEvaluator.evaluate(
+ stroke.getEndPointLength() / stroke.getTotalLength());
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/EndPointRatioEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/EndPointRatioEvaluator.java
new file mode 100644
index 000000000000..529fcec2710e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/EndPointRatioEvaluator.java
@@ -0,0 +1,30 @@
+/*
+ * 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 EndPointRatioEvaluator {
+ public static float evaluate(float value) {
+ float evaluation = 0.0f;
+ if (value < 0.85) evaluation++;
+ if (value < 0.75) evaluation++;
+ if (value < 0.65) evaluation++;
+ if (value < 0.55) evaluation++;
+ if (value < 0.45) evaluation++;
+ if (value < 0.35) evaluation++;
+ return evaluation;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
new file mode 100644
index 000000000000..735a7c4bad4a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
@@ -0,0 +1,299 @@
+/*
+ * 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;
+
+import android.content.Context;
+import android.database.ContentObserver;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.view.MotionEvent;
+
+import com.android.systemui.analytics.DataCollector;
+import com.android.systemui.statusbar.StatusBarState;
+
+/**
+ * When the phone is locked, listens to touch, sensor and phone events and sends them to
+ * DataCollector and HumanInteractionClassifier.
+ *
+ * It does not collect touch events when the bouncer shows up.
+ */
+public class FalsingManager implements SensorEventListener {
+ private static final String ENFORCE_BOUNCER = "falsing_manager_enforce_bouncer";
+
+ 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,
+ Sensor.TYPE_LIGHT,
+ Sensor.TYPE_ROTATION_VECTOR,
+ };
+
+ private final Handler mHandler = new Handler();
+ private final Context mContext;
+
+ private final SensorManager mSensorManager;
+ private final DataCollector mDataCollector;
+ private final HumanInteractionClassifier mHumanInteractionClassifier;
+
+ private static FalsingManager sInstance = null;
+
+ private boolean mEnforceBouncer = false;
+ private boolean mBouncerOn = false;
+ private boolean mSessionActive = false;
+ private int mState = StatusBarState.SHADE;
+
+ protected final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
+ @Override
+ public void onChange(boolean selfChange) {
+ updateConfiguration();
+ }
+ };
+
+ private FalsingManager(Context context) {
+ mContext = context;
+ mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
+ mDataCollector = DataCollector.getInstance(mContext);
+ mHumanInteractionClassifier = HumanInteractionClassifier.getInstance(mContext);
+
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Secure.getUriFor(ENFORCE_BOUNCER), false,
+ mSettingsObserver,
+ UserHandle.USER_ALL);
+
+ updateConfiguration();
+ }
+
+ public static FalsingManager getInstance(Context context) {
+ if (sInstance == null) {
+ sInstance = new FalsingManager(context);
+ }
+ return sInstance;
+ }
+
+ private void updateConfiguration() {
+ mEnforceBouncer = 0 != Settings.Secure.getInt(mContext.getContentResolver(),
+ ENFORCE_BOUNCER, 0);
+ }
+
+ private boolean sessionEntrypoint() {
+ if (!mSessionActive && isEnabled() &&
+ (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED)) {
+ onSessionStart();
+ return true;
+ }
+ return false;
+ }
+
+ private void sessionExitpoint() {
+ if (mSessionActive) {
+ mSessionActive = false;
+ mSensorManager.unregisterListener(this);
+ }
+ }
+
+ private void onSessionStart() {
+ mBouncerOn = false;
+ mSessionActive = true;
+
+ 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);
+ }
+ }
+ }
+
+ public boolean isClassiferEnabled() {
+ return mHumanInteractionClassifier.isEnabled();
+ }
+
+ private boolean isEnabled() {
+ return mHumanInteractionClassifier.isEnabled() || mDataCollector.isEnabled();
+ }
+
+ /**
+ * @return true if the classifier determined that this is not a human interacting with the phone
+ */
+ public boolean isFalseTouch() {
+ return mHumanInteractionClassifier.isFalseTouch();
+ }
+
+ @Override
+ public synchronized void onSensorChanged(SensorEvent event) {
+ mDataCollector.onSensorChanged(event);
+ mHumanInteractionClassifier.onSensorChanged(event);
+ }
+
+ @Override
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {
+ mDataCollector.onAccuracyChanged(sensor, accuracy);
+ }
+
+ public boolean shouldEnforceBouncer() {
+ return mEnforceBouncer;
+ }
+
+ public void setStatusBarState(int state) {
+ mState = state;
+ }
+
+ public void onScreenTurningOn() {
+ if (sessionEntrypoint()) {
+ mDataCollector.onScreenTurningOn();
+ }
+ }
+
+ public void onScreenOnFromTouch() {
+ if (sessionEntrypoint()) {
+ mDataCollector.onScreenOnFromTouch();
+ }
+ }
+
+ public void onScreenOff() {
+ mDataCollector.onScreenOff();
+ sessionExitpoint();
+ }
+
+ public void onSucccessfulUnlock() {
+ mDataCollector.onSucccessfulUnlock();
+ sessionExitpoint();
+ }
+
+ public void onBouncerShown() {
+ if (!mBouncerOn) {
+ mBouncerOn = true;
+ mDataCollector.onBouncerShown();
+ }
+ }
+
+ public void onBouncerHidden() {
+ if (mBouncerOn) {
+ mBouncerOn = false;
+ mDataCollector.onBouncerHidden();
+ }
+ }
+
+ public void onQsDown() {
+ mHumanInteractionClassifier.setType(Classifier.QUICK_SETTINGS);
+ mDataCollector.onQsDown();
+ }
+
+ public void setQsExpanded(boolean expanded) {
+ mDataCollector.setQsExpanded(expanded);
+ }
+
+ public void onTrackingStarted() {
+ mHumanInteractionClassifier.setType(Classifier.UNLOCK);
+ mDataCollector.onTrackingStarted();
+ }
+
+ public void onTrackingStopped() {
+ mDataCollector.onTrackingStopped();
+ }
+
+ public void onNotificationActive() {
+ mDataCollector.onNotificationActive();
+ }
+
+ public void onNotificationDoubleTap() {
+ mDataCollector.onNotificationDoubleTap();
+ }
+
+ public void setNotificationExpanded() {
+ mDataCollector.setNotificationExpanded();
+ }
+
+ public void onNotificatonStartDraggingDown() {
+ mHumanInteractionClassifier.setType(Classifier.NOTIFICATION_DRAG_DOWN);
+ mDataCollector.onNotificatonStartDraggingDown();
+ }
+
+ public void onNotificatonStopDraggingDown() {
+ mDataCollector.onNotificatonStopDraggingDown();
+ }
+
+ public void onNotificationDismissed() {
+ mDataCollector.onNotificationDismissed();
+ }
+
+ public void onNotificatonStartDismissing() {
+ mHumanInteractionClassifier.setType(Classifier.NOTIFICATION_DISMISS);
+ mDataCollector.onNotificatonStartDismissing();
+ }
+
+ public void onNotificatonStopDismissing() {
+ mDataCollector.onNotificatonStopDismissing();
+ }
+
+ public void onCameraOn() {
+ mDataCollector.onCameraOn();
+ }
+
+ public void onLeftAffordanceOn() {
+ mDataCollector.onLeftAffordanceOn();
+ }
+
+ public void onAffordanceSwipingStarted(boolean rightCorner) {
+ if (rightCorner) {
+ mHumanInteractionClassifier.setType(Classifier.RIGHT_AFFORDANCE);
+ } else {
+ mHumanInteractionClassifier.setType(Classifier.LEFT_AFFORDANCE);
+ }
+ mDataCollector.onAffordanceSwipingStarted(rightCorner);
+ }
+
+ public void onAffordanceSwipingAborted() {
+ mDataCollector.onAffordanceSwipingAborted();
+ }
+
+ public void onUnlockHintStarted() {
+ mDataCollector.onUnlockHintStarted();
+ }
+
+ public void onCameraHintStarted() {
+ mDataCollector.onCameraHintStarted();
+ }
+
+ public void onLeftAffordanceHintStarted() {
+ mDataCollector.onLeftAffordanceHintStarted();
+ }
+
+ public void onTouchEvent(MotionEvent event, int width, int height) {
+ if (mSessionActive && !mBouncerOn) {
+ mDataCollector.onTouchEvent(event, width, height);
+ mHumanInteractionClassifier.onTouchEvent(event);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/GestureClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/GestureClassifier.java
new file mode 100644
index 000000000000..11388fc49594
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/GestureClassifier.java
@@ -0,0 +1,32 @@
+/*
+ * 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;
+
+/**
+ * An abstract class for classifiers which classify the whole gesture (all the strokes which
+ * occurred from DOWN event to UP/CANCEL event)
+ */
+public abstract class GestureClassifier extends Classifier {
+
+ /**
+ * @param type the type of action for which this method is called
+ * @return a non-negative value which is used to determine whether the most recent gesture is a
+ * false interaction; the bigger the value the greater the chance that this a false
+ * interaction.
+ */
+ public abstract float getFalseTouchEvaluation(int type);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/HistoryEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/HistoryEvaluator.java
new file mode 100644
index 000000000000..85a9bee8d977
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/HistoryEvaluator.java
@@ -0,0 +1,112 @@
+/*
+ * 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;
+
+import java.util.ArrayList;
+
+/**
+ * Holds the evaluations for ended strokes and gestures. These values are decreased through time.
+ */
+public class HistoryEvaluator {
+ private static final float INTERVAL = 50.0f;
+ private static final float HISTORY_FACTOR = 0.9f;
+ private static final float EPSILON = 1e-5f;
+
+ private final ArrayList<Data> mStrokes = new ArrayList<>();
+ private final ArrayList<Data> mGestureWeights = new ArrayList<>();
+ private long mLastUpdate;
+
+ public HistoryEvaluator() {
+ mLastUpdate = System.currentTimeMillis();
+ }
+
+ public void addStroke(float evaluation) {
+ decayValue();
+ mStrokes.add(new Data(evaluation));
+ }
+
+ public void addGesture(float evaluation) {
+ decayValue();
+ mGestureWeights.add(new Data(evaluation));
+ }
+
+ /**
+ * Calculates the weighted average of strokes and adds to it the weighted average of gestures
+ */
+ public float getEvaluation() {
+ return weightedAverage(mStrokes) + weightedAverage(mGestureWeights);
+ }
+
+ private float weightedAverage(ArrayList<Data> list) {
+ float sumValue = 0.0f;
+ float sumWeight = 0.0f;
+ int size = list.size();
+ for (int i = 0; i < size; i++) {
+ Data data = list.get(i);
+ sumValue += data.evaluation * data.weight;
+ sumWeight += data.weight;
+ }
+
+ if (sumWeight == 0.0f) {
+ return 0.0f;
+ }
+
+ return sumValue / sumWeight;
+ }
+
+ private void decayValue() {
+ long currentTimeMillis = System.currentTimeMillis();
+
+ // All weights are multiplied by HISTORY_FACTOR after each INTERVAL milliseconds.
+ float factor = (float) Math.pow(HISTORY_FACTOR,
+ (float) (currentTimeMillis - mLastUpdate) / INTERVAL);
+
+ decayValue(mStrokes, factor);
+ decayValue(mGestureWeights, factor);
+ mLastUpdate = currentTimeMillis;
+ }
+
+ private void decayValue(ArrayList<Data> list, float factor) {
+ int size = list.size();
+ for (int i = 0; i < size; i++) {
+ list.get(i).weight *= factor;
+ }
+
+ // Removing evaluations with such small weights that they do not matter anymore
+ while (!list.isEmpty() && isZero(list.get(0).weight)) {
+ list.remove(0);
+ }
+ }
+
+ private boolean isZero(float x) {
+ return x <= EPSILON && x >= -EPSILON;
+ }
+
+ /**
+ * For each stroke it holds its initial value and the current weight. Initially the
+ * weight is set to 1.0
+ */
+ private static class Data {
+ public float evaluation;
+ public float weight;
+
+ public Data(float evaluation) {
+ this.evaluation = evaluation;
+ weight = 1.0f;
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
new file mode 100644
index 000000000000..0e45ac19469a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
@@ -0,0 +1,202 @@
+/*
+ * 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;
+
+import android.content.Context;
+import android.database.ContentObserver;
+import android.hardware.SensorEvent;
+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;
+
+/**
+ * An classifier trying to determine whether it is a human interacting with the phone or not.
+ */
+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();
+ private final Context mContext;
+
+ 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 = true;
+ private int mCurrentType = Classifier.GENERIC;
+
+ protected final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
+ @Override
+ public void onChange(boolean selfChange) {
+ updateConfiguration();
+ }
+ };
+
+ private HumanInteractionClassifier(Context context) {
+ mContext = context;
+ 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 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 LengthCountClassifier(mClassifierData));
+
+ mGestureClassifiers.add(new PointerCountClassifier(mClassifierData));
+ mGestureClassifiers.add(new ProximityClassifier(mClassifierData));
+
+ mStrokeClassifiersSize = mStrokeClassifiers.size();
+ mGestureClassifiersSize = mGestureClassifiers.size();
+
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Global.getUriFor(HIC_ENABLE), false,
+ mSettingsObserver,
+ UserHandle.USER_ALL);
+
+ updateConfiguration();
+ }
+
+ public static HumanInteractionClassifier getInstance(Context context) {
+ if (sInstance == null) {
+ sInstance = new HumanInteractionClassifier(context);
+ }
+ return sInstance;
+ }
+
+ private void updateConfiguration() {
+ mEnableClassifier = Build.IS_DEBUGGABLE && 0 != Settings.Global.getInt(
+ mContext.getContentResolver(),
+ HIC_ENABLE, 0);
+ }
+
+ public void setType(int type) {
+ mCurrentType = type;
+ }
+
+ @Override
+ public void onTouchEvent(MotionEvent event) {
+ if (!mEnableClassifier) {
+ return;
+ }
+
+ // 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();
+ }
+
+ int action = event.getActionMasked();
+ if (action == MotionEvent.ACTION_UP) {
+ mBufferedEvents.getFirst().setAction(MotionEvent.ACTION_UP);
+ addTouchEvent(mBufferedEvents.getFirst());
+ mBufferedEvents.clear();
+ }
+ } else {
+ addTouchEvent(event);
+ }
+ }
+
+ private void addTouchEvent(MotionEvent event) {
+ mClassifierData.update(event);
+
+ 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);
+ }
+
+ 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
+ public void onSensorChanged(SensorEvent event) {
+ for (int i = 0; i < mStrokeClassifiers.size(); i++) {
+ mStrokeClassifiers.get(i).onSensorChanged(event);
+ }
+
+ for (int i = 0; i < mGestureClassifiers.size(); i++) {
+ mGestureClassifiers.get(i).onSensorChanged(event);
+ }
+ }
+
+ public boolean isFalseTouch() {
+ if (mEnableClassifier) {
+ return mHistoryEvaluator.getEvaluation() >= 5.0f;
+ }
+ return false;
+ }
+
+ public boolean isEnabled() {
+ return mEnableClassifier;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/LengthCountClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/LengthCountClassifier.java
new file mode 100644
index 000000000000..1ea467bfb857
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/LengthCountClassifier.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 com.android.systemui.classifier;
+
+/**
+ * A classifier which looks at the ratio between the duration of the stroke and its number of
+ * points.
+ */
+public class LengthCountClassifier extends StrokeClassifier {
+ public LengthCountClassifier(ClassifierData classifierData) {
+ }
+
+ @Override
+ public float getFalseTouchEvaluation(int type, Stroke stroke) {
+ return LengthCountEvaluator.evaluate(stroke.getTotalLength() / stroke.getCount());
+ }
+} \ 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
new file mode 100644
index 000000000000..68f163d1916b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/LengthCountEvaluator.java
@@ -0,0 +1,33 @@
+/*
+ * 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 ratio between the length of the stroke and its number of
+ * points.
+ */
+public class LengthCountEvaluator {
+ public static float evaluate(float value) {
+ float evaluation = 0.0f;
+ if (value < 0.07) evaluation++;
+ if (value < 0.05) evaluation++;
+ if (value < 0.02) evaluation++;
+ if (value > 0.6) evaluation++;
+ if (value > 1.2) evaluation++;
+ return evaluation;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/Point.java b/packages/SystemUI/src/com/android/systemui/classifier/Point.java
new file mode 100644
index 000000000000..f3dc2be4144b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/Point.java
@@ -0,0 +1,83 @@
+/*
+ * 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 Point {
+ public float x;
+ public float y;
+ public long timeOffsetNano;
+
+ public Point(float x, float y) {
+ this.x = x;
+ this.y = y;
+ this.timeOffsetNano = 0;
+ }
+
+ public Point(float x, float y, long timeOffsetNano) {
+ this.x = x;
+ this.y = y;
+ this.timeOffsetNano = timeOffsetNano;
+ }
+
+ public boolean equals(Point p) {
+ return x == p.x && y == p.y;
+ }
+
+ public float dist(Point a) {
+ return (float) Math.hypot(a.x - x, a.y - y);
+ }
+
+ /**
+ * Calculates the cross product of vec(this, a) and vec(this, b) where vec(x,y) is the
+ * vector from point x to point y
+ */
+ public float crossProduct(Point a, Point b) {
+ return (a.x - x) * (b.y - y) - (a.y - y) * (b.x - x);
+ }
+
+ /**
+ * Calculates the dot product of vec(this, a) and vec(this, b) where vec(x,y) is the
+ * vector from point x to point y
+ */
+ public float dotProduct(Point a, Point b) {
+ return (a.x - x) * (b.x - x) + (a.y - y) * (b.y - y);
+ }
+
+ /**
+ * Calculates the angle in radians created by points (a, this, b). If any two of these points
+ * are the same, the method will return 0.0f
+ *
+ * @return the angle in radians
+ */
+ public float getAngle(Point a, Point b) {
+ float dist1 = dist(a);
+ float dist2 = dist(b);
+
+ if (dist1 == 0.0f || dist2 == 0.0f) {
+ return 0.0f;
+ }
+
+ float crossProduct = crossProduct(a, b);
+ float dotProduct = dotProduct(a, b);
+ float cos = Math.min(1.0f, Math.max(-1.0f, dotProduct / dist1 / dist2));
+ float angle = (float) Math.acos(cos);
+ if (crossProduct < 0.0) {
+ angle = 2.0f * (float) Math.PI - angle;
+ }
+ return angle;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java
new file mode 100644
index 000000000000..5097b635807e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.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 com.android.systemui.classifier;
+
+import android.view.MotionEvent;
+
+/**
+ * A classifier which looks at the total number of traces in the whole gesture.
+ */
+public class PointerCountClassifier extends GestureClassifier {
+ private int mCount;
+
+ public PointerCountClassifier(ClassifierData classifierData) {
+ mCount = 0;
+ }
+
+ @Override
+ public void onTouchEvent(MotionEvent event) {
+ int action = event.getActionMasked();
+
+ if (action == MotionEvent.ACTION_DOWN) {
+ mCount = 1;
+ }
+
+ if (action == MotionEvent.ACTION_POINTER_DOWN) {
+ ++mCount;
+ }
+ }
+
+ @Override
+ public float getFalseTouchEvaluation(int type) {
+ return PointerCountEvaluator.evaluate(mCount);
+ }
+}
diff --git a/packages/SystemUI/res/values-sw600dp-port/dimens.xml b/packages/SystemUI/src/com/android/systemui/classifier/PointerCountEvaluator.java
index 7dc91d164e2e..d7a3af0360af 100644
--- a/packages/SystemUI/res/values-sw600dp-port/dimens.xml
+++ b/packages/SystemUI/src/com/android/systemui/classifier/PointerCountEvaluator.java
@@ -1,21 +1,23 @@
-<?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.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* 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>
+ * limitations under the License
+ */
+
+package com.android.systemui.classifier;
+
+public class PointerCountEvaluator {
+ public static float evaluate(int value) {
+ return (value - 1) * (value - 1);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java
new file mode 100644
index 000000000000..69950640337f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.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.systemui.classifier;
+
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.view.MotionEvent;
+
+/**
+ * A classifier which looks at the proximity sensor during the gesture. It calculates the percentage
+ * the proximity sensor showing the near state during the whole gesture
+ */
+public class ProximityClassifier extends GestureClassifier {
+ private long mGestureStartTimeNano;
+ private long mNearStartTimeNano;
+ private long mNearDuration;
+ private boolean mNear;
+ private float mAverageNear;
+
+ public ProximityClassifier(ClassifierData classifierData) {
+ }
+
+ @Override
+ public void onSensorChanged(SensorEvent event) {
+ if (event.sensor.getType() == Sensor.TYPE_PROXIMITY) {
+ update(event.values[0] < event.sensor.getMaximumRange(), event.timestamp);
+ }
+ }
+
+ @Override
+ public void onTouchEvent(MotionEvent event) {
+ int action = event.getActionMasked();
+
+ if (action == MotionEvent.ACTION_DOWN) {
+ mGestureStartTimeNano = event.getEventTimeNano();
+ mNearStartTimeNano = event.getEventTimeNano();
+ mNearDuration = 0;
+ }
+
+ if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
+ update(mNear, event.getEventTimeNano());
+ long duration = event.getEventTimeNano() - mGestureStartTimeNano;
+
+ if (duration == 0) {
+ mAverageNear = mNear ? 1.0f : 0.0f;
+ } else {
+ mAverageNear = (float) mNearDuration / (float) duration;
+ }
+ }
+ }
+
+
+ /**
+ * @param near is the sensor showing the near state right now
+ * @param timestampNano time of this event in nanoseconds
+ */
+ private void update(boolean near, long timestampNano) {
+ // This if is necessary because MotionEvents and SensorEvents do not come in
+ // chronological order
+ if (timestampNano > mNearStartTimeNano) {
+ // if the state before was near then add the difference of the current time and
+ // mNearStartTimeNano to mNearDuration.
+ if (mNear) {
+ mNearDuration += timestampNano - mNearStartTimeNano;
+ }
+
+ // if the new state is near, set mNearStartTimeNano equal to this moment.
+ if (near) {
+ mNearStartTimeNano = timestampNano;
+ }
+ }
+ mNear = near;
+ }
+
+ @Override
+ public float getFalseTouchEvaluation(int type) {
+ return ProximityEvaluator.evaluate(mAverageNear, type);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/ProximityEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/ProximityEvaluator.java
new file mode 100644
index 000000000000..91002bf1291c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/ProximityEvaluator.java
@@ -0,0 +1,29 @@
+/*
+ * 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 ProximityEvaluator {
+ public static float evaluate(float value, int type) {
+ float evaluation = 0.0f;
+ float threshold = 0.1f;
+ if (type == Classifier.QUICK_SETTINGS) {
+ threshold = 1.0f;
+ }
+ if (value >= threshold) evaluation += 2.0;
+ return evaluation;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/SpeedClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/SpeedClassifier.java
new file mode 100644
index 000000000000..81b78c7ecdfe
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/SpeedClassifier.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.systemui.classifier;
+
+/**
+ * A classifier that looks at the speed of the stroke. It calculates the speed of a stroke in
+ * inches per second.
+ */
+public class SpeedClassifier extends StrokeClassifier {
+ private final float NANOS_TO_SECONDS = 1e9f;
+
+ public SpeedClassifier(ClassifierData classifierData) {
+ }
+
+ @Override
+ public float getFalseTouchEvaluation(int type, Stroke stroke) {
+ float duration = (float) stroke.getDurationNanos() / NANOS_TO_SECONDS;
+ if (duration == 0.0f) {
+ return SpeedEvaluator.evaluate(0.0f);
+ }
+ return SpeedEvaluator.evaluate(stroke.getTotalLength() / duration);
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/SpeedEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/SpeedEvaluator.java
new file mode 100644
index 000000000000..c0e4a2ddc89a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/SpeedEvaluator.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 SpeedEvaluator {
+ public static float evaluate(float value) {
+ float evaluation = 0.0f;
+ if (value < 4.0 || value > 35.0) evaluation += 1.0;
+ if (value < 2.2) evaluation += 1.0;
+ if (value > 50.0) evaluation += 1.0;
+ return evaluation;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/SpeedRatioEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/SpeedRatioEvaluator.java
new file mode 100644
index 000000000000..349aa9ed49d6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/SpeedRatioEvaluator.java
@@ -0,0 +1,26 @@
+/*
+ * 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 SpeedRatioEvaluator {
+ public static float evaluate(float value) {
+ float evaluation = 0.0f;
+ if (value > 9.0) ++evaluation;
+ if (value > 18.0) ++evaluation;
+ return evaluation;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/SpeedVarianceClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/SpeedVarianceClassifier.java
new file mode 100644
index 000000000000..9a30fe1a425c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/SpeedVarianceClassifier.java
@@ -0,0 +1,124 @@
+/*
+ * 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;
+
+import android.view.MotionEvent;
+
+import java.lang.Math;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+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
+ * the last point of a stroke because the UP event comes in with some delay and this ruins the
+ * smoothness of this curve
+ */
+public class SpeedVarianceClassifier extends StrokeClassifier {
+ private HashMap<Stroke, Data> mStrokeMap = new HashMap<>();
+
+ public SpeedVarianceClassifier(ClassifierData classifierData) {
+ mClassifierData = classifierData;
+ }
+
+ @Override
+ public void onTouchEvent(MotionEvent event) {
+ int action = event.getActionMasked();
+
+ if (action == MotionEvent.ACTION_DOWN) {
+ mStrokeMap.clear();
+ }
+
+ for (int i = 0; i < event.getPointerCount(); i++) {
+ Stroke stroke = mClassifierData.getStroke(event.getPointerId(i));
+
+ if (mStrokeMap.get(stroke) == null) {
+ mStrokeMap.put(stroke, new Data());
+ }
+
+ if (action != MotionEvent.ACTION_UP && action != MotionEvent.ACTION_CANCEL
+ && !(action == MotionEvent.ACTION_POINTER_UP && i == event.getActionIndex())) {
+ mStrokeMap.get(stroke).addPoint(
+ stroke.getPoints().get(stroke.getPoints().size() - 1));
+ }
+ }
+ }
+
+ @Override
+ public float getFalseTouchEvaluation(int type, Stroke stroke) {
+ return SpeedVarianceEvaluator.evaluate(mStrokeMap.get(stroke).getAnglesVariance());
+ }
+
+ private static class Data {
+ private final float DURATION_SCALE = 1e8f;
+ private final float LENGTH_SCALE = 1.0f;
+
+ private List<Point> mLastThreePoints = new ArrayList<>();
+ private Point mPreviousPoint;
+ private float mPreviousAngle;
+ private float mSumSquares;
+ private float mSum;
+ private float mCount;
+ private float mDist;
+
+ public Data() {
+ mPreviousPoint = null;
+ mPreviousAngle = (float) Math.PI;
+ mSumSquares = 0.0f;
+ mSum = 0.0f;
+ mCount = 1.0f;
+ mDist = 0.0f;
+ }
+
+ public void addPoint(Point point) {
+ if (mPreviousPoint != null) {
+ mDist += mPreviousPoint.dist(point);
+ }
+
+ mPreviousPoint = point;
+ Point speedPoint = new Point((float) point.timeOffsetNano / DURATION_SCALE,
+ mDist / LENGTH_SCALE);
+
+ // Checking if the added point is different than the previously added point
+ // Repetitions are being ignored so that proper angles are calculated.
+ if (mLastThreePoints.isEmpty()
+ || !mLastThreePoints.get(mLastThreePoints.size() - 1).equals(speedPoint)) {
+ mLastThreePoints.add(speedPoint);
+ if (mLastThreePoints.size() == 4) {
+ mLastThreePoints.remove(0);
+
+ float angle = mLastThreePoints.get(1).getAngle(mLastThreePoints.get(0),
+ mLastThreePoints.get(2));
+
+ float difference = angle - mPreviousAngle;
+ mSum += difference;
+ mSumSquares += difference * difference;
+ mCount += 1.0;
+ mPreviousAngle = angle;
+ }
+ }
+ }
+
+ public float getAnglesVariance() {
+ return mSumSquares / mCount - (mSum / mCount) * (mSum / mCount);
+ }
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/SpeedVarianceEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/SpeedVarianceEvaluator.java
new file mode 100644
index 000000000000..8f9a7e159638
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/SpeedVarianceEvaluator.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.classifier;
+
+public class SpeedVarianceEvaluator {
+ public static float evaluate(float value) {
+ float evaluation = 0.0f;
+ if (value > 0.06) evaluation += 1.0;
+ if (value > 0.15) evaluation += 1.0;
+ if (value > 0.3) evaluation += 1.0;
+ if (value > 0.6) evaluation += 1.0;
+ return evaluation;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/Stroke.java b/packages/SystemUI/src/com/android/systemui/classifier/Stroke.java
new file mode 100644
index 000000000000..fb04d3e73a2d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/Stroke.java
@@ -0,0 +1,71 @@
+/*
+ * 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;
+
+import java.util.ArrayList;
+
+/**
+ * Contains data about a stroke (a single trace, all the events from a given id from the
+ * DOWN/POINTER_DOWN event till the UP/POINTER_UP/CANCEL event.)
+ */
+public class Stroke {
+ private final float NANOS_TO_SECONDS = 1e9f;
+
+ private ArrayList<Point> mPoints = new ArrayList<>();
+ private long mStartTimeNano;
+ private long mEndTimeNano;
+ private float mLength;
+ private final float mDpi;
+
+ 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 / mDpi, y / mDpi, eventTimeNano - mStartTimeNano);
+ if (!mPoints.isEmpty()) {
+ mLength += mPoints.get(mPoints.size() - 1).dist(point);
+ }
+ mPoints.add(point);
+ }
+
+ public int getCount() {
+ return mPoints.size();
+ }
+
+ public float getTotalLength() {
+ return mLength;
+ }
+
+ public float getEndPointLength() {
+ return mPoints.get(0).dist(mPoints.get(mPoints.size() - 1));
+ }
+
+ public long getDurationNanos() {
+ return mEndTimeNano - mStartTimeNano;
+ }
+
+ public float getDurationSeconds() {
+ return (float) getDurationNanos() / NANOS_TO_SECONDS;
+ }
+
+ public ArrayList<Point> getPoints() {
+ return mPoints;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/StrokeClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/StrokeClassifier.java
new file mode 100644
index 000000000000..5da392f31d63
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/StrokeClassifier.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 com.android.systemui.classifier;
+
+/**
+ * An abstract class for classifiers which classify each stroke separately.
+ */
+public abstract class StrokeClassifier extends Classifier {
+
+ /**
+ * @param type the type of action for which this method is called
+ * @param stroke the stroke for which the evaluation will be calculated
+ * @return a non-negative value which is used to determine whether this a false touch; the
+ * bigger the value the greater the chance that this a false touch
+ */
+ public abstract float getFalseTouchEvaluation(int type, Stroke stroke);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 0be3069c51c2..2ea1e43b39a2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -68,13 +68,15 @@ import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.SystemUI;
+import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.statusbar.phone.FingerprintUnlockController;
-import com.android.systemui.analytics.LockedPhoneAnalytics;
import com.android.systemui.statusbar.phone.PhoneStatusBar;
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.phone.StatusBarWindowManager;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
@@ -153,6 +155,7 @@ public class KeyguardViewMediator extends SystemUI {
private static final int NOTIFY_STARTED_WAKING_UP = 21;
private static final int NOTIFY_SCREEN_TURNED_ON = 22;
private static final int NOTIFY_SCREEN_TURNED_OFF = 23;
+ private static final int NOTIFY_STARTED_GOING_TO_SLEEP = 24;
/**
* The default amount of time we stay awake (used for all key input)
@@ -650,6 +653,7 @@ public class KeyguardViewMediator extends SystemUI {
final boolean lockImmediately =
mLockPatternUtils.getPowerButtonInstantlyLocks(currentUser)
|| !mLockPatternUtils.isSecure(currentUser);
+ long timeout = getLockTimeout();
if (mExitSecureCallback != null) {
if (DEBUG) Log.d(TAG, "pending exit secure callback cancelled");
@@ -664,9 +668,9 @@ public class KeyguardViewMediator extends SystemUI {
}
} else if (mShowing) {
mPendingReset = true;
- } else if (why == WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT
+ } else if ((why == WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT && timeout > 0)
|| (why == WindowManagerPolicy.OFF_BECAUSE_OF_USER && !lockImmediately)) {
- doKeyguardLaterLocked();
+ doKeyguardLaterLocked(timeout);
} else if (!mLockPatternUtils.isLockScreenDisabled(currentUser)) {
mPendingLock = true;
}
@@ -675,6 +679,8 @@ public class KeyguardViewMediator extends SystemUI {
playSounds(true);
}
}
+ KeyguardUpdateMonitor.getInstance(mContext).dispatchStartedGoingToSleep(why);
+ notifyStartedGoingToSleep();
}
public void onFinishedGoingToSleep(int why) {
@@ -700,7 +706,7 @@ public class KeyguardViewMediator extends SystemUI {
KeyguardUpdateMonitor.getInstance(mContext).dispatchFinishedGoingToSleep(why);
}
- private void doKeyguardLaterLocked() {
+ private long getLockTimeout() {
// if the screen turned off because of timeout or the user hit the power button
// and we don't need to lock immediately, set an alarm
// to enable it a little bit later (i.e, give the user a chance
@@ -729,23 +735,30 @@ public class KeyguardViewMediator extends SystemUI {
} else {
timeout = lockAfterTimeout;
}
+ return timeout;
+ }
- if (timeout <= 0) {
- // Lock now
+ private void doKeyguardLaterLocked() {
+ long timeout = getLockTimeout();
+ if (timeout == 0) {
doKeyguardLocked(null);
} else {
- // Lock in the future
- long when = SystemClock.elapsedRealtime() + timeout;
- Intent intent = new Intent(DELAYED_KEYGUARD_ACTION);
- intent.putExtra("seq", mDelayedShowingSequence);
- PendingIntent sender = PendingIntent.getBroadcast(mContext,
- 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
- mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, when, sender);
- if (DEBUG) Log.d(TAG, "setting alarm to turn off keyguard, seq = "
- + mDelayedShowingSequence);
+ doKeyguardLaterLocked(timeout);
}
}
+ private void doKeyguardLaterLocked(long timeout) {
+ // Lock in the future
+ long when = SystemClock.elapsedRealtime() + timeout;
+ Intent intent = new Intent(DELAYED_KEYGUARD_ACTION);
+ intent.putExtra("seq", mDelayedShowingSequence);
+ PendingIntent sender = PendingIntent.getBroadcast(mContext,
+ 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
+ mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, when, sender);
+ if (DEBUG) Log.d(TAG, "setting alarm to turn off keyguard, seq = "
+ + mDelayedShowingSequence);
+ }
+
private void cancelDoKeyguardLaterLocked() {
mDelayedShowingSequence++;
}
@@ -908,9 +921,27 @@ public class KeyguardViewMediator extends SystemUI {
} catch (RemoteException e) {
Slog.w(TAG, "Failed to call onKeyguardExitResult(false)", e);
}
+ } else if (!isSecure()) {
+
+ // Keyguard is not secure, no need to do anything, and we don't need to reshow
+ // the Keyguard after the client releases the Keyguard lock.
+ mExternallyEnabled = true;
+ mNeedToReshowWhenReenabled = false;
+ updateInputRestricted();
+ try {
+ callback.onKeyguardExitResult(true);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to call onKeyguardExitResult(false)", e);
+ }
} else {
- mExitSecureCallback = callback;
- verifyUnlockLocked();
+
+ // Since we prevent apps from hiding the Keyguard if we are secure, this should be
+ // a no-op as well.
+ try {
+ callback.onKeyguardExitResult(false);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to call onKeyguardExitResult(false)", e);
+ }
}
}
}
@@ -1096,6 +1127,11 @@ public class KeyguardViewMediator extends SystemUI {
mHandler.sendEmptyMessage(VERIFY_UNLOCK);
}
+ private void notifyStartedGoingToSleep() {
+ if (DEBUG) Log.d(TAG, "notifyStartedGoingToSleep");
+ mHandler.sendEmptyMessage(NOTIFY_STARTED_GOING_TO_SLEEP);
+ }
+
private void notifyFinishedGoingToSleep() {
if (DEBUG) Log.d(TAG, "notifyFinishedGoingToSleep");
mHandler.sendEmptyMessage(NOTIFY_FINISHED_GOING_TO_SLEEP);
@@ -1207,6 +1243,9 @@ public class KeyguardViewMediator extends SystemUI {
case VERIFY_UNLOCK:
handleVerifyUnlock();
break;
+ case NOTIFY_STARTED_GOING_TO_SLEEP:
+ handleNotifyStartedGoingToSleep();
+ break;
case NOTIFY_FINISHED_GOING_TO_SLEEP:
handleNotifyFinishedGoingToSleep();
break;
@@ -1242,7 +1281,7 @@ public class KeyguardViewMediator extends SystemUI {
case START_KEYGUARD_EXIT_ANIM:
StartKeyguardExitAnimParams params = (StartKeyguardExitAnimParams) msg.obj;
handleStartKeyguardExitAnimation(params.startTime, params.fadeoutDuration);
- LockedPhoneAnalytics.getInstance(mContext).onSucccessfulUnlock();
+ FalsingManager.getInstance(mContext).onSucccessfulUnlock();
break;
case KEYGUARD_DONE_PENDING_TIMEOUT:
Log.w(TAG, "Timeout while waiting for activity drawn!");
@@ -1544,6 +1583,13 @@ public class KeyguardViewMediator extends SystemUI {
}
}
+ private void handleNotifyStartedGoingToSleep() {
+ synchronized (KeyguardViewMediator.this) {
+ if (DEBUG) Log.d(TAG, "handleNotifyStartedGoingToSleep");
+ mStatusBarKeyguardViewManager.onStartedGoingToSleep();
+ }
+ }
+
/**
* Handle message sent by {@link #notifyFinishedGoingToSleep()}
* @see #NOTIFY_FINISHED_GOING_TO_SLEEP
@@ -1641,6 +1687,30 @@ public class KeyguardViewMediator extends SystemUI {
return mViewMediatorCallback;
}
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.print(" mSystemReady: "); pw.println(mSystemReady);
+ pw.print(" mBootCompleted: "); pw.println(mBootCompleted);
+ pw.print(" mBootSendUserPresent: "); pw.println(mBootSendUserPresent);
+ pw.print(" mExternallyEnabled: "); pw.println(mExternallyEnabled);
+ pw.print(" mNeedToReshowWhenReenabled: "); pw.println(mNeedToReshowWhenReenabled);
+ pw.print(" mShowing: "); pw.println(mShowing);
+ pw.print(" mInputRestricted: "); pw.println(mInputRestricted);
+ pw.print(" mOccluded: "); pw.println(mOccluded);
+ pw.print(" mDelayedShowingSequence: "); pw.println(mDelayedShowingSequence);
+ pw.print(" mExitSecureCallback: "); pw.println(mExitSecureCallback);
+ pw.print(" mDeviceInteractive: "); pw.println(mDeviceInteractive);
+ pw.print(" mGoingToSleep: "); pw.println(mGoingToSleep);
+ pw.print(" mHiding: "); pw.println(mHiding);
+ pw.print(" mWaitingUntilKeyguardVisible: "); pw.println(mWaitingUntilKeyguardVisible);
+ pw.print(" mKeyguardDonePending: "); pw.println(mKeyguardDonePending);
+ pw.print(" mHideAnimationRun: "); pw.println(mHideAnimationRun);
+ pw.print(" mPendingReset: "); pw.println(mPendingReset);
+ pw.print(" mPendingLock: "); pw.println(mPendingLock);
+ pw.print(" mWakeAndUnlocking: "); pw.println(mWakeAndUnlocking);
+ pw.print(" mDrawnCallback: "); pw.println(mDrawnCallback);
+ }
+
private static class StartKeyguardExitAnimParams {
long startTime;
diff --git a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
index 7f68e290f3a0..f39f3026f26b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
@@ -160,7 +160,7 @@ public class RingtonePlayer extends SystemUI {
throw new SecurityException("Async playback only available from system UID.");
}
if (UserHandle.ALL.equals(user)) {
- user = UserHandle.OWNER;
+ user = UserHandle.SYSTEM;
}
mAsyncPlayer.play(getContextForUser(user), uri, looping, aa);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QWifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QWifiTile.java
index 87194fb840d1..b1572754fb6b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/QWifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QWifiTile.java
@@ -17,6 +17,7 @@
package com.android.systemui.qs.tiles;
import com.android.systemui.qs.QSTileView;
+import com.android.systemui.statusbar.policy.WifiIcons;
/** Quick settings tile: Wifi **/
public class QWifiTile extends WifiTile {
@@ -29,4 +30,23 @@ public class QWifiTile extends WifiTile {
public int getTileType() {
return QSTileView.QS_TYPE_QUICK;
}
+
+ @Override
+ protected void handleUpdateState(SignalState state, Object arg) {
+ super.handleUpdateState(state, arg);
+
+ CallbackInfo cb = (CallbackInfo) arg;
+ if (cb == null) {
+ cb = mSignalCallback.mInfo;
+ }
+ boolean wifiConnected = cb.enabled && (cb.wifiSignalIconId > 0) && (cb.enabledDesc != null);
+
+ if (state.enabled && wifiConnected) {
+ // Only show full signal here.
+ state.icon = ResourceIcon.get(WifiIcons.QS_WIFI_SIGNAL_STRENGTH[1][4]);
+ }
+ // No activity in the quick toggle.
+ state.activityIn = false;
+ state.activityOut = false;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index 3295e14e0ae5..91e02183818f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -48,7 +48,7 @@ public class WifiTile extends QSTile<QSTile.SignalState> {
private final WifiDetailAdapter mDetailAdapter;
private final QSTile.SignalState mStateBeforeClick = newTileState();
- private final WifiSignalCallback mSignalCallback = new WifiSignalCallback();
+ protected final WifiSignalCallback mSignalCallback = new WifiSignalCallback();
private final boolean mAlwaysDetail;
@@ -200,7 +200,7 @@ public class WifiTile extends QSTile<QSTile.SignalState> {
return string;
}
- private static final class CallbackInfo {
+ protected static final class CallbackInfo {
boolean enabled;
boolean connected;
int wifiSignalIconId;
@@ -223,7 +223,7 @@ public class WifiTile extends QSTile<QSTile.SignalState> {
}
}
- private final class WifiSignalCallback extends SignalCallbackAdapter {
+ protected final class WifiSignalCallback extends SignalCallbackAdapter {
final CallbackInfo mInfo = new CallbackInfo();
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
index a4acf831dfa9..978166438303 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
@@ -29,8 +29,6 @@ public class Constants {
}
public static class DebugFlags {
- // Enable this with any other debug flag to see more info
- public static final boolean Verbose = false;
public static class App {
// Enables debug drawing for the transition thumbnail
@@ -39,14 +37,8 @@ public class Constants {
public static final boolean EnableTaskFiltering = false;
// Enables dismiss-all
public static final boolean EnableDismissAll = false;
- // Enables debug mode
- public static final boolean EnableDebugMode = false;
- // Enables the search bar layout
- public static final boolean EnableSearchLayout = true;
// Enables the thumbnail alpha on the front-most task
public static final boolean EnableThumbnailAlphaOnFrontmost = false;
- // Enables all system stacks to show up in the same recents stack
- public static final boolean EnableMultiStackToSingleStack = true;
// This disables the bitmap and icon caches
public static final boolean DisableBackgroundCache = false;
// Enables the simulated task affiliations
@@ -65,7 +57,6 @@ public class Constants {
public static class Values {
public static class App {
public static int AppWidgetHostId = 1024;
- public static String DebugModeVersion = "A";
}
public static class TaskStackView {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index 0cfa7a18032d..a3e89f2f06c4 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -116,7 +116,7 @@ public class Recents extends SystemUI
/** Preloads the next task */
public void run() {
// Temporarily skip this if multi stack is enabled
- if (mConfig.multiStackEnabled) return;
+ if (mConfig.multiWindowEnabled) return;
RecentsConfiguration config = RecentsConfiguration.getInstance();
if (config.svelteLevel == RecentsConfiguration.SVELTE_NONE) {
@@ -151,7 +151,8 @@ public class Recents extends SystemUI
public void onReceive(Context context, Intent intent) {
switch (intent.getAction()) {
case ACTION_PROXY_NOTIFY_RECENTS_VISIBLITY_TO_OWNER:
- visibilityChanged(intent.getBooleanExtra(EXTRA_RECENTS_VISIBILITY, false));
+ visibilityChanged(context,
+ intent.getBooleanExtra(EXTRA_RECENTS_VISIBILITY, false));
break;
case ACTION_PROXY_SCREEN_PINNING_REQUEST_TO_OWNER:
onStartScreenPinning(context);
@@ -160,7 +161,6 @@ public class Recents extends SystemUI
}
}
- static RecentsComponent.Callbacks sRecentsComponentCallbacks;
static RecentsTaskLoadPlan sInstanceLoadPlan;
static Recents sInstance;
@@ -176,7 +176,6 @@ public class Recents extends SystemUI
// Task launching
RecentsConfiguration mConfig;
- Rect mWindowRect = new Rect();
Rect mTaskStackBounds = new Rect();
Rect mSystemInsets = new Rect();
TaskViewTransform mTmpTransform = new TaskViewTransform();
@@ -372,9 +371,9 @@ public class Recents extends SystemUI
if (topTask != null && !mSystemServicesProxy.isRecentsTopMost(topTask, topTaskHome)) {
sInstanceLoadPlan.preloadRawTasks(topTaskHome.value);
loader.preloadTasks(sInstanceLoadPlan, topTaskHome.value);
- TaskStack top = sInstanceLoadPlan.getAllTaskStacks().get(0);
- if (top.getTaskCount() > 0) {
- preCacheThumbnailTransitionBitmapAsync(topTask, top, mDummyStackView,
+ TaskStack stack = sInstanceLoadPlan.getTaskStack();
+ if (stack.getTaskCount() > 0) {
+ preCacheThumbnailTransitionBitmapAsync(topTask, stack, mDummyStackView,
topTaskHome.value);
}
}
@@ -388,16 +387,10 @@ public class Recents extends SystemUI
void showRelativeAffiliatedTask(boolean showNextTask) {
// Return early if there is no focused stack
int focusedStackId = mSystemServicesProxy.getFocusedStack();
- TaskStack focusedStack = null;
RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext);
loader.preloadTasks(plan, true /* isTopTaskHome */);
- if (mConfig.multiStackEnabled) {
- if (focusedStackId < 0) return;
- focusedStack = plan.getTaskStack(focusedStackId);
- } else {
- focusedStack = plan.getAllTaskStacks().get(0);
- }
+ TaskStack focusedStack = plan.getTaskStack();
// Return early if there are no tasks in the focused stack
if (focusedStack == null || focusedStack.getTaskCount() == 0) return;
@@ -502,10 +495,13 @@ public class Recents extends SystemUI
/** Prepares the header bar layout. */
void reloadHeaderBarLayout() {
Resources res = mContext.getResources();
- mWindowRect = mSystemServicesProxy.getWindowRect();
+ 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);
+ // TODO: We can't rely on this anymore since the activity context will yield different
+ // resources while multiwindow is enabled
mConfig = RecentsConfiguration.reinitialize(mContext, mSystemServicesProxy);
mConfig.updateOnConfigurationChange();
Rect searchBarBounds = new Rect();
@@ -513,10 +509,10 @@ public class Recents extends SystemUI
// 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(mWindowRect.width(), mWindowRect.height(),
+ mConfig.getSearchBarBounds(windowRect,
mStatusBarHeight, searchBarBounds);
}
- mConfig.getAvailableTaskStackBounds(mWindowRect.width(), mWindowRect.height(),
+ mConfig.getAvailableTaskStackBounds(windowRect,
mStatusBarHeight, (mConfig.hasTransposedNavBar ? mNavBarWidth : 0), searchBarBounds,
mTaskStackBounds);
if (mConfig.isLandscape && mConfig.hasTransposedNavBar) {
@@ -531,7 +527,7 @@ public class Recents extends SystemUI
TaskStackViewLayoutAlgorithm algo = mDummyStackView.getStackAlgorithm();
Rect taskStackBounds = new Rect(mTaskStackBounds);
taskStackBounds.bottom -= mSystemInsets.bottom;
- algo.computeRects(mWindowRect.width(), mWindowRect.height(), taskStackBounds);
+ algo.computeRects(windowRect.width(), windowRect.height(), taskStackBounds);
Rect taskViewSize = algo.getUntransformedTaskViewSize();
int taskBarHeight = res.getDimensionPixelSize(R.dimen.recents_task_bar_height);
synchronized (mHeaderBarLock) {
@@ -540,6 +536,7 @@ public class Recents extends SystemUI
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);
}
}
@@ -740,7 +737,10 @@ public class Recents extends SystemUI
/** Starts the recents activity */
void startRecentsActivity(ActivityManager.RunningTaskInfo topTask, boolean isTopTaskHome) {
RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
- RecentsConfiguration.reinitialize(mContext, mSystemServicesProxy);
+ // Don't reinitialize the configuration completely here, since it has the wrong context,
+ // only update the parts that we can get from any context
+ RecentsConfiguration config = RecentsConfiguration.getInstance();
+ config.reinitializeWithApplicationContext(mContext, mSystemServicesProxy);
if (sInstanceLoadPlan == null) {
// Create a new load plan if onPreloadRecents() was never triggered
@@ -749,10 +749,9 @@ public class Recents extends SystemUI
// 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.multiStackEnabled) {
+ if (mConfig.multiWindowEnabled) {
loader.preloadTasks(sInstanceLoadPlan, true);
- ArrayList<TaskStack> stacks = sInstanceLoadPlan.getAllTaskStacks();
- TaskStack stack = stacks.get(0);
+ TaskStack stack = sInstanceLoadPlan.getTaskStack();
mDummyStackView.updateMinMaxScrollForStack(stack, mTriggeredFromAltTab, true);
TaskStackViewLayoutAlgorithm.VisibilityReport stackVr =
mDummyStackView.computeStackVisibilityReport();
@@ -765,8 +764,7 @@ public class Recents extends SystemUI
if (!sInstanceLoadPlan.hasTasks()) {
loader.preloadTasks(sInstanceLoadPlan, isTopTaskHome);
}
- ArrayList<TaskStack> stacks = sInstanceLoadPlan.getAllTaskStacks();
- TaskStack stack = stacks.get(0);
+ TaskStack stack = sInstanceLoadPlan.getTaskStack();
// Prepare the dummy stack for the transition
mDummyStackView.updateMinMaxScrollForStack(stack, mTriggeredFromAltTab, isTopTaskHome);
@@ -841,18 +839,12 @@ public class Recents extends SystemUI
mCanReuseTaskStackViews = true;
}
- /** Sets the RecentsComponent callbacks. */
- @Override
- public void setCallback(RecentsComponent.Callbacks cb) {
- sRecentsComponentCallbacks = cb;
- }
-
/** Notifies the callbacks that the visibility of Recents has changed. */
@ProxyFromAnyToSystemUser
public static void notifyVisibilityChanged(Context context, SystemServicesProxy ssp,
boolean visible) {
if (ssp.isForegroundUserSystem()) {
- visibilityChanged(visible);
+ visibilityChanged(context, visible);
} else {
Intent intent = createLocalBroadcastIntent(context,
ACTION_PROXY_NOTIFY_RECENTS_VISIBLITY_TO_OWNER);
@@ -860,9 +852,13 @@ public class Recents extends SystemUI
context.sendBroadcastAsUser(intent, UserHandle.SYSTEM);
}
}
- static void visibilityChanged(boolean visible) {
- if (sRecentsComponentCallbacks != null) {
- sRecentsComponentCallbacks.onVisibilityChanged(visible);
+ static void visibilityChanged(Context context, boolean visible) {
+ // For the primary user, the context for the SystemUI component is the SystemUIApplication
+ SystemUIApplication app = (SystemUIApplication)
+ getInstanceAndStartIfNeeded(context.getApplicationContext()).mContext;
+ PhoneStatusBar statusBar = app.getComponent(PhoneStatusBar.class);
+ if (statusBar != null) {
+ statusBar.updateRecentsVisibility(visible);
}
}
@@ -880,7 +876,7 @@ public class Recents extends SystemUI
static void onStartScreenPinning(Context context) {
// For the primary user, the context for the SystemUI component is the SystemUIApplication
SystemUIApplication app = (SystemUIApplication)
- getInstanceAndStartIfNeeded(context).mContext;
+ getInstanceAndStartIfNeeded(context.getApplicationContext()).mContext;
PhoneStatusBar statusBar = app.getComponent(PhoneStatusBar.class);
if (statusBar != null) {
statusBar.showScreenPinningRequest(false);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index d0876fa3577f..c53e57325c3d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -25,6 +25,7 @@ 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;
@@ -37,14 +38,12 @@ import com.android.internal.logging.MetricsLogger;
import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.recents.misc.Console;
-import com.android.systemui.recents.misc.DebugTrigger;
import com.android.systemui.recents.misc.ReferenceCountedTrigger;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.model.RecentsTaskLoadPlan;
import com.android.systemui.recents.model.RecentsTaskLoader;
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.model.TaskStack;
-import com.android.systemui.recents.views.DebugOverlayView;
import com.android.systemui.recents.views.RecentsView;
import com.android.systemui.recents.views.SystemBarScrimViews;
import com.android.systemui.recents.views.ViewAnimation;
@@ -56,8 +55,7 @@ import java.util.ArrayList;
* The main Recents activity that is started from AlternateRecentsComponent.
*/
public class RecentsActivity extends Activity implements RecentsView.RecentsViewCallbacks,
- RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks,
- DebugOverlayView.DebugOverlayViewCallbacks {
+ RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks {
RecentsConfiguration mConfig;
long mLastTabKeyEventTime;
@@ -66,9 +64,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
RecentsView mRecentsView;
SystemBarScrimViews mScrimViews;
ViewStub mEmptyViewStub;
- ViewStub mDebugOverlayStub;
View mEmptyView;
- DebugOverlayView mDebugOverlay;
// Resize task debug
RecentsResizeTaskDialog mResizeTaskDebugDialog;
@@ -175,16 +171,6 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
}
};
- /**
- * A custom debug trigger to listen for a debug key chord.
- */
- final DebugTrigger mDebugTrigger = new DebugTrigger(new Runnable() {
- @Override
- public void run() {
- onDebugModeTriggered();
- }
- });
-
/** Updates the set of recent tasks */
void updateRecentsTasks() {
// If AlternateRecentsComponent has preloaded a load plan, then use that to prevent
@@ -205,10 +191,10 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
loadOpts.numVisibleTaskThumbnails = mConfig.launchedNumVisibleThumbnails;
loader.loadTasks(this, plan, loadOpts);
- ArrayList<TaskStack> stacks = plan.getAllTaskStacks();
+ TaskStack stack = plan.getTaskStack();
mConfig.launchedWithNoRecentTasks = !plan.hasTasks();
if (!mConfig.launchedWithNoRecentTasks) {
- mRecentsView.setTaskStacks(stacks);
+ mRecentsView.setTaskStack(stack);
}
// Create the home intent runnable
@@ -224,20 +210,16 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
R.anim.recents_to_launcher_exit));
// Mark the task that is the launch target
- int taskStackCount = stacks.size();
int launchTaskIndexInStack = 0;
if (mConfig.launchedToTaskId != -1) {
- for (int i = 0; i < taskStackCount; i++) {
- TaskStack stack = stacks.get(i);
- 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) {
- t.isLaunchTarget = true;
- launchTaskIndexInStack = tasks.size() - j - 1;
- break;
- }
+ 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) {
+ t.isLaunchTarget = true;
+ launchTaskIndexInStack = tasks.size() - j - 1;
+ break;
}
}
}
@@ -278,11 +260,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
MetricsLogger.count(this, "overview_source_home", 1);
}
// Keep track of the total stack task count
- int taskCount = 0;
- for (int i = 0; i < stacks.size(); i++) {
- TaskStack stack = stacks.get(i);
- taskCount += stack.getTaskCount();
- }
+ int taskCount = stack.getTaskCount();
MetricsLogger.histogram(this, "overview_task_count", taskCount);
}
@@ -359,9 +337,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);
- mDebugOverlayStub = (ViewStub) findViewById(R.id.debug_overlay_stub);
mScrimViews = new SystemBarScrimViews(this, mConfig);
- inflateDebugOverlay();
// Bind the search app widget when we first start up
mSearchWidgetInfo = ssp.getOrBindSearchAppWidget(this, mAppWidgetHost);
@@ -373,27 +349,10 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
registerReceiver(mSystemBroadcastReceiver, filter);
}
- /** Inflates the debug overlay if debug mode is enabled. */
- void inflateDebugOverlay() {
- if (!Constants.DebugFlags.App.EnableDebugMode) return;
-
- if (mConfig.debugModeEnabled && mDebugOverlay == null) {
- // Inflate the overlay and seek bars
- mDebugOverlay = (DebugOverlayView) mDebugOverlayStub.inflate();
- mDebugOverlay.setCallbacks(this);
- mRecentsView.setDebugOverlay(mDebugOverlay);
- }
- }
-
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
-
- // Clear any debug rects
- if (mDebugOverlay != null) {
- mDebugOverlay.clear();
- }
}
@Override
@@ -545,8 +504,6 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
default:
break;
}
- // Pass through the debug trigger
- mDebugTrigger.onKeyEvent(keyCode);
return super.onKeyDown(keyCode, event);
}
@@ -564,33 +521,6 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
dismissRecentsToFocusedTaskOrHome(true);
}
- /** Called when debug mode is triggered */
- public void onDebugModeTriggered() {
- if (mConfig.developerOptionsEnabled) {
- if (Prefs.getBoolean(this, Prefs.Key.DEBUG_MODE_ENABLED, false /* boolean */)) {
- // Disable the debug mode
- Prefs.remove(this, Prefs.Key.DEBUG_MODE_ENABLED);
- mConfig.debugModeEnabled = false;
- inflateDebugOverlay();
- if (mDebugOverlay != null) {
- mDebugOverlay.disable();
- }
- } else {
- // Enable the debug mode
- Prefs.putBoolean(this, Prefs.Key.DEBUG_MODE_ENABLED, true);
- mConfig.debugModeEnabled = true;
- inflateDebugOverlay();
- if (mDebugOverlay != null) {
- mDebugOverlay.enable();
- }
- }
- Toast.makeText(this, "Debug mode (" + Constants.Values.App.DebugModeVersion + ") " +
- (mConfig.debugModeEnabled ? "Enabled" : "Disabled") + ", please restart Recents now",
- Toast.LENGTH_SHORT).show();
- }
- }
-
-
/**** RecentsResizeTaskDialog ****/
private RecentsResizeTaskDialog getResizeTaskDebugDialog() {
@@ -662,16 +592,4 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
mRecentsView.setSearchBar(null);
}
}
-
- /**** DebugOverlayView.DebugOverlayViewCallbacks ****/
-
- @Override
- public void onPrimarySeekBarChanged(float progress) {
- // Do nothing
- }
-
- @Override
- public void onSecondarySeekBarChanged(float progress) {
- // Do nothing
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index dfe7e964fec4..a59eb3048be3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -134,7 +134,7 @@ public class RecentsConfiguration {
public boolean fakeShadows;
/** Dev options and global settings */
- public boolean multiStackEnabled;
+ public boolean multiWindowEnabled;
public boolean lockToAppEnabled;
public boolean developerOptionsEnabled;
public boolean debugModeEnabled;
@@ -166,7 +166,7 @@ public class RecentsConfiguration {
sInstance.update(context);
sPrevConfigurationHashCode = configHashCode;
}
- sInstance.updateOnReinitialize(context, ssp);
+ sInstance.reinitializeWithApplicationContext(context.getApplicationContext(), ssp);
return sInstance;
}
@@ -276,14 +276,14 @@ public class RecentsConfiguration {
systemInsets.set(insets);
}
- /** Updates the states that need to be re-read whenever we re-initialize. */
- void updateOnReinitialize(Context context, SystemServicesProxy ssp) {
+ /** Updates the states that need to be re-read from the application context. */
+ void reinitializeWithApplicationContext(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;
- multiStackEnabled = "true".equals(ssp.getSystemProperty("persist.sys.debug.multi_window"));
+ multiWindowEnabled = "true".equals(ssp.getSystemProperty("persist.sys.debug.multi_window"));
}
/** Called when the configuration has changed, and we want to reset any configuration specific
@@ -320,14 +320,16 @@ public class RecentsConfiguration {
* Returns the task stack bounds in the current orientation. These bounds do not account for
* the system insets.
*/
- public void getAvailableTaskStackBounds(int windowWidth, int windowHeight, int topInset,
+ 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(0, topInset, windowWidth - rightInset, windowHeight);
+ taskStackBounds.set(windowBounds.left, windowBounds.top + topInset,
+ windowBounds.right - rightInset, windowBounds.bottom);
} else {
// In portrait, the search bar appears on the top (which already has the inset)
- taskStackBounds.set(0, searchBarBounds.bottom, windowWidth, windowHeight);
+ taskStackBounds.set(windowBounds.left, searchBarBounds.bottom,
+ windowBounds.right, windowBounds.bottom);
}
}
@@ -335,16 +337,17 @@ public class RecentsConfiguration {
* Returns the search bar bounds in the current orientation. These bounds do not account for
* the system insets.
*/
- public void getSearchBarBounds(int windowWidth, int windowHeight, int topInset,
- Rect searchBarSpaceBounds) {
+ 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
- searchBarSpaceBounds.set(0, topInset, searchBarSize, windowHeight);
+ searchBarSpaceBounds.set(windowBounds.left, windowBounds.top + topInset,
+ windowBounds.left + searchBarSize, windowBounds.bottom);
} else {
// In portrait, the search bar appears on the top
- searchBarSpaceBounds.set(0, topInset, windowWidth, topInset + searchBarSize);
+ searchBarSpaceBounds.set(windowBounds.left, windowBounds.top + topInset,
+ windowBounds.right, windowBounds.top + topInset + searchBarSize);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java
index 300ea2a4777b..85f5b5d4d18b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java
@@ -16,6 +16,7 @@
package com.android.systemui.recents;
+import android.app.ActivityManager;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
@@ -24,19 +25,16 @@ import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Rect;
import android.os.Bundle;
-import android.util.Pair;
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;
import com.android.systemui.recents.model.Task;
-import com.android.systemui.recents.RecentsActivity;
import com.android.systemui.recents.views.RecentsView;
-import java.util.ArrayList;
-
/**
* A helper for the dialogs that show when task debugging is on.
*/
@@ -54,10 +52,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},
@@ -76,6 +82,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;
@@ -86,13 +98,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);
@@ -104,7 +114,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;
+ }
}
});
}
@@ -113,7 +133,7 @@ public class RecentsResizeTaskDialog extends DialogFragment {
builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
- dismiss();
+ dismissAllowingStateLoss();
}
});
@@ -122,7 +142,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) {
@@ -197,7 +217,7 @@ public class RecentsResizeTaskDialog extends DialogFragment {
break;
case PLACE_FULL:
// Nothing to change.
- mBounds[0] = null;
+ mBounds[0] = new Rect();
break;
}
@@ -211,12 +231,12 @@ 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
// current app configuration.
- if (RecentsConfiguration.getInstance().multiStackEnabled) {
+ if (RecentsConfiguration.getInstance().multiWindowEnabled) {
for (int i = additionalTasks; i >= 0; --i) {
if (mTasks[i] != null) {
mSsp.setTaskResizeable(mTasks[i].key.id);
@@ -233,12 +253,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/misc/DebugTrigger.java b/packages/SystemUI/src/com/android/systemui/recents/misc/DebugTrigger.java
deleted file mode 100644
index fbf8a8669b70..000000000000
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/DebugTrigger.java
+++ /dev/null
@@ -1,70 +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.systemui.recents.misc;
-
-import android.os.Handler;
-import android.os.SystemClock;
-import android.view.KeyEvent;
-import com.android.systemui.recents.Constants;
-
-/**
- * A trigger for catching a debug chord.
- * We currently use volume up then volume down to trigger this mode.
- */
-public class DebugTrigger {
-
- Handler mHandler;
- Runnable mTriggeredRunnable;
-
- int mLastKeyCode;
- long mLastKeyCodeTime;
-
- public DebugTrigger(Runnable triggeredRunnable) {
- mHandler = new Handler();
- mTriggeredRunnable = triggeredRunnable;
- }
-
- /** Resets the debug trigger */
- void reset() {
- mLastKeyCode = 0;
- mLastKeyCodeTime = 0;
- }
-
- /**
- * Processes a key event and tests if it is a part of the trigger. If the chord is complete,
- * then we just call the callback.
- */
- public void onKeyEvent(int keyCode) {
- if (!Constants.DebugFlags.App.EnableDebugMode) return;
-
- if (mLastKeyCode == 0) {
- if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
- mLastKeyCode = keyCode;
- mLastKeyCodeTime = SystemClock.uptimeMillis();
- return;
- }
- } else {
- if (mLastKeyCode == KeyEvent.KEYCODE_VOLUME_UP &&
- keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
- if ((SystemClock.uptimeMillis() - mLastKeyCodeTime) < 750) {
- mTriggeredRunnable.run();
- }
- }
- }
- reset();
- }
-}
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 bead1b0c165f..a2d7d0108362 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -32,6 +32,7 @@ import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.graphics.Bitmap;
@@ -282,6 +283,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,16 +662,36 @@ public class SystemServicesProxy {
}
/**
+ * 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.
*/
public Rect getWindowRect() {
Rect windowRect = new Rect();
- if (mWm == null) return windowRect;
+ if (mIam == null) return windowRect;
- Point p = new Point();
- mWm.getDefaultDisplay().getRealSize(p);
- windowRect.set(0, 0, p.x, p.y);
- return windowRect;
+ try {
+ // Use the home stack bounds
+ ActivityManager.StackInfo stackInfo = mIam.getStackInfo(ActivityManager.HOME_STACK_ID);
+ if (stackInfo != null) {
+ windowRect.set(stackInfo.bounds);
+ }
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ } finally {
+ return windowRect;
+ }
}
/** Starts an activity from recents. */
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 b8015c09a585..649cb4db0fb1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
@@ -20,12 +20,10 @@ import android.app.ActivityManager;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
-import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.UserHandle;
import android.util.Log;
import android.util.SparseArray;
-import com.android.systemui.recents.Constants;
import com.android.systemui.recents.RecentsConfiguration;
import com.android.systemui.recents.misc.SystemServicesProxy;
@@ -63,7 +61,7 @@ public class RecentsTaskLoadPlan {
SystemServicesProxy mSystemServicesProxy;
List<ActivityManager.RecentTaskInfo> mRawTasks;
- SparseArray<TaskStack> mStacks = new SparseArray<>();
+ TaskStack mStack;
HashMap<Task.ComponentNameKey, ActivityInfoHandle> mActivityInfoCache =
new HashMap<Task.ComponentNameKey, ActivityInfoHandle>();
@@ -96,11 +94,8 @@ public class RecentsTaskLoadPlan {
// This activity info cache will be used for both preloadPlan() and executePlan()
mActivityInfoCache.clear();
- // TODO (multi-display): Currently assume the primary display
- Rect displayBounds = mSystemServicesProxy.getWindowRect();
-
Resources res = mContext.getResources();
- SparseArray<ArrayList<Task>> stacksTasks = new SparseArray<>();
+ ArrayList<Task> stackTasks = new ArrayList<>();
if (mRawTasks == null) {
preloadRawTasks(isTopTaskHome);
}
@@ -152,37 +147,13 @@ public class RecentsTaskLoadPlan {
task.thumbnail = loader.getAndUpdateThumbnail(taskKey, mSystemServicesProxy, false);
if (DEBUG) Log.d(TAG, "\tthumbnail: " + taskKey + ", " + task.thumbnail);
- if (!mConfig.multiStackEnabled ||
- Constants.DebugFlags.App.EnableMultiStackToSingleStack) {
- int firstStackId = 0;
- ArrayList<Task> stackTasks = stacksTasks.get(firstStackId);
- if (stackTasks == null) {
- stackTasks = new ArrayList<>();
- stacksTasks.put(firstStackId, stackTasks);
- }
- stackTasks.add(task);
- } else {
- ArrayList<Task> stackTasks = stacksTasks.get(t.stackId);
- if (stackTasks == null) {
- stackTasks = new ArrayList<>();
- stacksTasks.put(t.stackId, stackTasks);
- }
- stackTasks.add(task);
- }
+ stackTasks.add(task);
}
// Initialize the stacks
- mStacks.clear();
- int stackCount = stacksTasks.size();
- for (int i = 0; i < stackCount; i++) {
- int stackId = stacksTasks.keyAt(i);
- ArrayList<Task> stackTasks = stacksTasks.valueAt(i);
- TaskStack stack = new TaskStack(stackId);
- stack.setBounds(displayBounds, displayBounds);
- stack.setTasks(stackTasks);
- stack.createAffiliatedGroupings(mConfig);
- mStacks.put(stackId, stack);
- }
+ mStack = new TaskStack();
+ mStack.setTasks(stackTasks);
+ mStack.createAffiliatedGroupings(mConfig);
}
/**
@@ -197,92 +168,70 @@ public class RecentsTaskLoadPlan {
Resources res = mContext.getResources();
// Iterate through each of the tasks and load them according to the load conditions.
- int stackCount = mStacks.size();
- for (int j = 0; j < stackCount; j++) {
- ArrayList<Task> tasks = mStacks.valueAt(j).getTasks();
- int taskCount = tasks.size();
- for (int i = 0; i < taskCount; i++) {
- ActivityManager.RecentTaskInfo t = mRawTasks.get(i);
- Task task = tasks.get(i);
- Task.TaskKey taskKey = task.key;
-
- // Get an existing activity info handle if possible
- Task.ComponentNameKey cnKey = taskKey.getComponentNameKey();
- ActivityInfoHandle infoHandle;
- boolean hadCachedActivityInfo = false;
- if (mActivityInfoCache.containsKey(cnKey)) {
- infoHandle = mActivityInfoCache.get(cnKey);
- hadCachedActivityInfo = true;
- } else {
- infoHandle = new ActivityInfoHandle();
- }
+ ArrayList<Task> tasks = mStack.getTasks();
+ int taskCount = tasks.size();
+ for (int i = 0; i < taskCount; i++) {
+ ActivityManager.RecentTaskInfo t = mRawTasks.get(i);
+ Task task = tasks.get(i);
+ Task.TaskKey taskKey = task.key;
+
+ // Get an existing activity info handle if possible
+ Task.ComponentNameKey cnKey = taskKey.getComponentNameKey();
+ ActivityInfoHandle infoHandle;
+ boolean hadCachedActivityInfo = false;
+ if (mActivityInfoCache.containsKey(cnKey)) {
+ infoHandle = mActivityInfoCache.get(cnKey);
+ hadCachedActivityInfo = true;
+ } else {
+ infoHandle = new ActivityInfoHandle();
+ }
- boolean isRunningTask = (task.key.id == opts.runningTaskId);
- boolean isVisibleTask = i >= (taskCount - opts.numVisibleTasks);
- boolean isVisibleThumbnail = i >= (taskCount - opts.numVisibleTaskThumbnails);
+ boolean isRunningTask = (task.key.id == opts.runningTaskId);
+ boolean isVisibleTask = i >= (taskCount - opts.numVisibleTasks);
+ boolean isVisibleThumbnail = i >= (taskCount - opts.numVisibleTaskThumbnails);
- // If requested, skip the running task
- if (opts.onlyLoadPausedActivities && isRunningTask) {
- continue;
- }
+ // If requested, skip the running task
+ if (opts.onlyLoadPausedActivities && isRunningTask) {
+ continue;
+ }
- if (opts.loadIcons && (isRunningTask || isVisibleTask)) {
- if (task.activityIcon == null) {
- if (DEBUG) Log.d(TAG, "\tLoading icon: " + taskKey);
- task.activityIcon = loader.getAndUpdateActivityIcon(taskKey,
- t.taskDescription, mSystemServicesProxy, res, infoHandle, true);
- }
+ if (opts.loadIcons && (isRunningTask || isVisibleTask)) {
+ if (task.activityIcon == null) {
+ if (DEBUG) Log.d(TAG, "\tLoading icon: " + taskKey);
+ task.activityIcon = loader.getAndUpdateActivityIcon(taskKey,
+ t.taskDescription, mSystemServicesProxy, res, infoHandle, true);
}
- if (opts.loadThumbnails && (isRunningTask || isVisibleThumbnail)) {
- if (task.thumbnail == null || isRunningTask) {
- if (DEBUG) Log.d(TAG, "\tLoading thumbnail: " + taskKey);
- if (mConfig.svelteLevel <= RecentsConfiguration.SVELTE_LIMIT_CACHE) {
- task.thumbnail = loader.getAndUpdateThumbnail(taskKey,
- mSystemServicesProxy, true);
- } else if (mConfig.svelteLevel == RecentsConfiguration.SVELTE_DISABLE_CACHE) {
- loadQueue.addTask(task);
- }
+ }
+ if (opts.loadThumbnails && (isRunningTask || isVisibleThumbnail)) {
+ if (task.thumbnail == null || isRunningTask) {
+ if (DEBUG) Log.d(TAG, "\tLoading thumbnail: " + taskKey);
+ if (mConfig.svelteLevel <= RecentsConfiguration.SVELTE_LIMIT_CACHE) {
+ task.thumbnail = loader.getAndUpdateThumbnail(taskKey,
+ mSystemServicesProxy, true);
+ } else if (mConfig.svelteLevel == RecentsConfiguration.SVELTE_DISABLE_CACHE) {
+ loadQueue.addTask(task);
}
}
-
- // Update the activity info cache
- if (!hadCachedActivityInfo && infoHandle.info != null) {
- mActivityInfoCache.put(cnKey, infoHandle);
- }
}
- }
- }
- /**
- * Returns all TaskStacks from the preloaded list of recent tasks.
- */
- public ArrayList<TaskStack> getAllTaskStacks() {
- ArrayList<TaskStack> stacks = new ArrayList<TaskStack>();
- int stackCount = mStacks.size();
- for (int i = 0; i < stackCount; i++) {
- stacks.add(mStacks.valueAt(i));
- }
- // Ensure that we have at least one stack
- if (stacks.isEmpty()) {
- stacks.add(new TaskStack());
+ // Update the activity info cache
+ if (!hadCachedActivityInfo && infoHandle.info != null) {
+ mActivityInfoCache.put(cnKey, infoHandle);
+ }
}
- return stacks;
}
/**
- * Returns a specific TaskStack from the preloaded list of recent tasks.
+ * Returns the TaskStack from the preloaded list of recent tasks.
*/
- public TaskStack getTaskStack(int stackId) {
- return mStacks.get(stackId);
+ public TaskStack getTaskStack() {
+ return mStack;
}
/** Returns whether there are any tasks in any stacks. */
public boolean hasTasks() {
- int stackCount = mStacks.size();
- for (int i = 0; i < stackCount; i++) {
- if (mStacks.valueAt(i).getTaskCount() > 0) {
- return true;
- }
+ if (mStack != null) {
+ return mStack.getTaskCount() > 0;
}
return false;
}
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 5aaea15ff007..515e5784412a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -17,7 +17,6 @@
package com.android.systemui.recents.model;
import android.graphics.Color;
-import android.graphics.Rect;
import com.android.systemui.recents.Constants;
import com.android.systemui.recents.RecentsConfiguration;
import com.android.systemui.recents.misc.NamedCounter;
@@ -177,35 +176,17 @@ public class TaskStack {
// The task offset to apply to a task id as a group affiliation
static final int IndividualTaskIdOffset = 1 << 16;
- public final int id;
- public final Rect stackBounds = new Rect();
- public final Rect displayBounds = new Rect();
-
FilteredTaskList mTaskList = new FilteredTaskList();
TaskStackCallbacks mCb;
ArrayList<TaskGrouping> mGroups = new ArrayList<TaskGrouping>();
HashMap<Integer, TaskGrouping> mAffinitiesGroups = new HashMap<Integer, TaskGrouping>();
- public TaskStack() {
- this(0);
- }
-
- public TaskStack(int stackId) {
- id = stackId;
- }
-
/** Sets the callbacks for this task stack. */
public void setCallbacks(TaskStackCallbacks cb) {
mCb = cb;
}
- /** Sets the bounds of this stack. */
- public void setBounds(Rect stackBounds, Rect displayBounds) {
- this.stackBounds.set(stackBounds);
- this.displayBounds.set(displayBounds);
- }
-
/** Resets this TaskStack. */
public void reset() {
mCb = null;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/DebugOverlayView.java b/packages/SystemUI/src/com/android/systemui/recents/views/DebugOverlayView.java
deleted file mode 100644
index 452830d3b5fd..000000000000
--- a/packages/SystemUI/src/com/android/systemui/recents/views/DebugOverlayView.java
+++ /dev/null
@@ -1,190 +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.systemui.recents.views;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.util.AttributeSet;
-import android.util.Pair;
-import android.view.View;
-import android.widget.FrameLayout;
-import android.widget.SeekBar;
-import com.android.systemui.R;
-import com.android.systemui.recents.RecentsConfiguration;
-
-import java.util.ArrayList;
-
-/**
- * A full screen overlay layer that allows us to draw views from throughout the system on the top
- * most layer.
- */
-public class DebugOverlayView extends FrameLayout implements SeekBar.OnSeekBarChangeListener {
-
- public interface DebugOverlayViewCallbacks {
- public void onPrimarySeekBarChanged(float progress);
- public void onSecondarySeekBarChanged(float progress);
- }
-
- final static int sCornerRectSize = 50;
-
- RecentsConfiguration mConfig;
- DebugOverlayViewCallbacks mCb;
-
- ArrayList<Pair<Rect, Integer>> mRects = new ArrayList<Pair<Rect, Integer>>();
- String mText;
- Paint mDebugOutline = new Paint();
- Paint mTmpPaint = new Paint();
- Rect mTmpRect = new Rect();
- boolean mEnabled = true;
-
- SeekBar mPrimarySeekBar;
- SeekBar mSecondarySeekBar;
-
- public DebugOverlayView(Context context) {
- this(context, null);
- }
-
- public DebugOverlayView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public DebugOverlayView(Context context, AttributeSet attrs, int defStyleAttr) {
- this(context, attrs, defStyleAttr, 0);
- }
-
- public DebugOverlayView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
- mConfig = RecentsConfiguration.getInstance();
- mDebugOutline.setColor(0xFFff0000);
- mDebugOutline.setStyle(Paint.Style.STROKE);
- mDebugOutline.setStrokeWidth(8f);
- setWillNotDraw(false);
- }
-
- public void setCallbacks(DebugOverlayViewCallbacks cb) {
- mCb = cb;
- }
-
- @Override
- protected void onFinishInflate() {
- mPrimarySeekBar = (SeekBar) findViewById(R.id.debug_seek_bar_1);
- mPrimarySeekBar.setOnSeekBarChangeListener(this);
- mSecondarySeekBar = (SeekBar) findViewById(R.id.debug_seek_bar_2);
- mSecondarySeekBar.setOnSeekBarChangeListener(this);
- }
-
- /** Enables the debug overlay drawing. */
- public void enable() {
- mEnabled = true;
- setVisibility(View.VISIBLE);
- }
-
- /** Disables the debug overlay drawing. */
- public void disable() {
- mEnabled = false;
- setVisibility(View.GONE);
- }
-
- /** Clears all debug rects. */
- public void clear() {
- mRects.clear();
- }
-
- /** Adds a rect to be drawn. */
- void addRect(Rect r, int color) {
- mRects.add(new Pair<Rect, Integer>(r, color));
- invalidate();
- }
-
- /** Adds a view's global rect to be drawn. */
- void addViewRect(View v, int color) {
- Rect vr = new Rect();
- v.getGlobalVisibleRect(vr);
- mRects.add(new Pair<Rect, Integer>(vr, color));
- invalidate();
- }
-
- /** Adds a rect, relative to a given view to be drawn. */
- void addRectRelativeToView(View v, Rect r, int color) {
- Rect vr = new Rect();
- v.getGlobalVisibleRect(vr);
- r.offsetTo(vr.left, vr.top);
- mRects.add(new Pair<Rect, Integer>(r, color));
- invalidate();
- }
-
- /** Sets the debug text at the bottom of the screen. */
- void setText(String message) {
- mText = message;
- invalidate();
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- addRect(new Rect(0, 0, sCornerRectSize, sCornerRectSize), 0xFFff0000);
- addRect(new Rect(getMeasuredWidth() - sCornerRectSize, getMeasuredHeight() - sCornerRectSize,
- getMeasuredWidth(), getMeasuredHeight()), 0xFFff0000);
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- if (mEnabled) {
- // Draw the outline
- canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mDebugOutline);
-
- // Draw the rects
- int numRects = mRects.size();
- for (int i = 0; i < numRects; i++) {
- Pair<Rect, Integer> r = mRects.get(i);
- mTmpPaint.setColor(r.second);
- canvas.drawRect(r.first, mTmpPaint);
- }
-
- // Draw the text
- if (mText != null && mText.length() > 0) {
- mTmpPaint.setColor(0xFFff0000);
- mTmpPaint.setTextSize(60);
- mTmpPaint.getTextBounds(mText, 0, 1, mTmpRect);
- canvas.drawText(mText, 10f, getMeasuredHeight() - mTmpRect.height() - mConfig.systemInsets.bottom, mTmpPaint);
- }
- }
- }
-
- /**** SeekBar.OnSeekBarChangeListener Implementation ****/
-
- @Override
- public void onStopTrackingTouch(SeekBar seekBar) {
- // Do nothing
- }
-
- @Override
- public void onStartTrackingTouch(SeekBar seekBar) {
- // Do nothing
- }
-
- @Override
- public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
- if (seekBar == mPrimarySeekBar) {
- mCb.onPrimarySeekBarChanged((float) progress / mPrimarySeekBar.getMax());
- } else if (seekBar == mSecondarySeekBar) {
- mCb.onSecondarySeekBarChanged((float) progress / mSecondarySeekBar.getMax());
- }
- }
-}
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 509ad1b638f2..41adbed8fd3d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java
@@ -28,7 +28,6 @@ import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.drawable.Drawable;
import android.util.Log;
-
import com.android.systemui.R;
import com.android.systemui.recents.RecentsConfiguration;
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 651b29a19469..9685a245879c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -78,11 +78,9 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
RecentsConfiguration mConfig;
LayoutInflater mInflater;
- DebugOverlayView mDebugOverlay;
- RecentsViewLayoutAlgorithm mLayoutAlgorithm;
ArrayList<TaskStack> mStacks;
- List<TaskStackView> mTaskStackViews = new ArrayList<>();
+ TaskStackView mTaskStackView;
RecentsAppWidgetHostView mSearchBar;
RecentsViewCallbacks mCb;
@@ -102,7 +100,6 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
super(context, attrs, defStyleAttr, defStyleRes);
mConfig = RecentsConfiguration.getInstance();
mInflater = LayoutInflater.from(context);
- mLayoutAlgorithm = new RecentsViewLayoutAlgorithm(mConfig);
}
/** Sets the callbacks */
@@ -110,67 +107,37 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
mCb = cb;
}
- /** Sets the debug overlay */
- public void setDebugOverlay(DebugOverlayView overlay) {
- mDebugOverlay = overlay;
- }
-
/** Set/get the bsp root node */
- public void setTaskStacks(ArrayList<TaskStack> stacks) {
- int numStacks = stacks.size();
-
- // Remove all/extra stack views
- int numTaskStacksToKeep = 0; // Keep no tasks if we are recreating the layout
+ public void setTaskStack(TaskStack stack) {
if (mConfig.launchedReuseTaskStackViews) {
- numTaskStacksToKeep = Math.min(mTaskStackViews.size(), numStacks);
- }
- for (int i = mTaskStackViews.size() - 1; i >= numTaskStacksToKeep; i--) {
- removeView(mTaskStackViews.remove(i));
- }
-
- // Update the stack views that we are keeping
- for (int i = 0; i < numTaskStacksToKeep; i++) {
- TaskStackView tsv = mTaskStackViews.get(i);
- // If onRecentsHidden is not triggered, we need to the stack view again here
- tsv.reset();
- tsv.setStack(stacks.get(i));
- }
-
- // Add remaining/recreate stack views
- mStacks = stacks;
- for (int i = mTaskStackViews.size(); i < numStacks; i++) {
- TaskStack stack = stacks.get(i);
- TaskStackView stackView = new TaskStackView(getContext(), stack);
- stackView.setCallbacks(this);
- addView(stackView);
- mTaskStackViews.add(stackView);
- }
-
- // Enable debug mode drawing on all the stacks if necessary
- if (mConfig.debugModeEnabled) {
- for (int i = mTaskStackViews.size() - 1; i >= 0; i--) {
- TaskStackView stackView = mTaskStackViews.get(i);
- stackView.setDebugOverlay(mDebugOverlay);
+ if (mTaskStackView != null) {
+ // If onRecentsHidden is not triggered, we need to the stack view again here
+ mTaskStackView.reset();
+ mTaskStackView.setStack(stack);
+ } else {
+ mTaskStackView = new TaskStackView(getContext(), stack);
+ mTaskStackView.setCallbacks(this);
+ addView(mTaskStackView);
}
+ } else {
+ if (mTaskStackView != null) {
+ removeView(mTaskStackView);
+ }
+ mTaskStackView = new TaskStackView(getContext(), stack);
+ mTaskStackView.setCallbacks(this);
+ addView(mTaskStackView);
}
// Trigger a new layout
requestLayout();
}
- /** Gets the list of task views */
- List<TaskStackView> getTaskStackViews() {
- return mTaskStackViews;
- }
-
/** Gets the next task in the stack - or if the last - the top task */
public Task getNextTaskOrTopTask(Task taskToSearch) {
Task returnTask = null;
boolean found = false;
- List<TaskStackView> stackViews = getTaskStackViews();
- int stackCount = stackViews.size();
- for (int i = stackCount - 1; i >= 0; --i) {
- TaskStack stack = stackViews.get(i).getStack();
+ if (mTaskStackView != null) {
+ TaskStack stack = mTaskStackView.getStack();
ArrayList<Task> taskList = stack.getTasks();
// Iterate the stack views and try and find the focused task
for (int j = taskList.size() - 1; j >= 0; --j) {
@@ -190,20 +157,16 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
/** Launches the focused task from the first stack if possible */
public boolean launchFocusedTask() {
- // Get the first stack view
- List<TaskStackView> stackViews = getTaskStackViews();
- int stackCount = stackViews.size();
- for (int i = 0; i < stackCount; i++) {
- TaskStackView stackView = stackViews.get(i);
- TaskStack stack = stackView.getStack();
+ if (mTaskStackView != null) {
+ TaskStack stack = mTaskStackView.getStack();
// Iterate the stack views and try and find the focused task
- List<TaskView> taskViews = stackView.getTaskViews();
+ List<TaskView> taskViews = mTaskStackView.getTaskViews();
int taskViewCount = taskViews.size();
for (int j = 0; j < taskViewCount; j++) {
TaskView tv = taskViews.get(j);
Task task = tv.getTask();
if (tv.isFocusedTask()) {
- onTaskViewClicked(stackView, tv, stack, task, false, false, null);
+ onTaskViewClicked(mTaskStackView, tv, stack, task, false, false, null);
return true;
}
}
@@ -213,19 +176,16 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
/** Launches a given task. */
public boolean launchTask(Task task, Rect taskBounds) {
- // Get the first stack view
- List<TaskStackView> stackViews = getTaskStackViews();
- int stackCount = stackViews.size();
- for (int i = 0; i < stackCount; i++) {
- TaskStackView stackView = stackViews.get(i);
- TaskStack stack = stackView.getStack();
+ if (mTaskStackView != null) {
+ TaskStack stack = mTaskStackView.getStack();
// Iterate the stack views and try and find the given task.
- List<TaskView> taskViews = stackView.getTaskViews();
+ List<TaskView> taskViews = mTaskStackView.getTaskViews();
int taskViewCount = taskViews.size();
for (int j = 0; j < taskViewCount; j++) {
TaskView tv = taskViews.get(j);
if (tv.getTask() == task) {
- onTaskViewClicked(stackView, tv, stack, task, false, true, taskBounds);
+ onTaskViewClicked(mTaskStackView, tv, stack, task, false, taskBounds != null,
+ taskBounds);
return true;
}
}
@@ -235,12 +195,8 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
/** Launches the task that Recents was launched from, if possible */
public boolean launchPreviousTask() {
- // Get the first stack view
- List<TaskStackView> stackViews = getTaskStackViews();
- int stackCount = stackViews.size();
- for (int i = 0; i < stackCount; i++) {
- TaskStackView stackView = stackViews.get(i);
- TaskStack stack = stackView.getStack();
+ if (mTaskStackView != null) {
+ TaskStack stack = mTaskStackView.getStack();
ArrayList<Task> tasks = stack.getTasks();
// Find the launch task in the stack
@@ -249,8 +205,8 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
for (int j = 0; j < taskCount; j++) {
if (tasks.get(j).isLaunchTarget) {
Task task = tasks.get(j);
- TaskView tv = stackView.getChildViewForTask(task);
- onTaskViewClicked(stackView, tv, stack, task, false, false, null);
+ TaskView tv = mTaskStackView.getChildViewForTask(task);
+ onTaskViewClicked(mTaskStackView, tv, stack, task, false, false, null);
return true;
}
}
@@ -264,12 +220,8 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
// We have to increment/decrement the post animation trigger in case there are no children
// to ensure that it runs
ctx.postAnimationTrigger.increment();
-
- List<TaskStackView> stackViews = getTaskStackViews();
- int stackCount = stackViews.size();
- for (int i = 0; i < stackCount; i++) {
- TaskStackView stackView = stackViews.get(i);
- stackView.startEnterRecentsAnimation(ctx);
+ if (mTaskStackView != null) {
+ mTaskStackView.startEnterRecentsAnimation(ctx);
}
ctx.postAnimationTrigger.decrement();
}
@@ -279,11 +231,8 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
// We have to increment/decrement the post animation trigger in case there are no children
// to ensure that it runs
ctx.postAnimationTrigger.increment();
- List<TaskStackView> stackViews = getTaskStackViews();
- int stackCount = stackViews.size();
- for (int i = 0; i < stackCount; i++) {
- TaskStackView stackView = stackViews.get(i);
- stackView.startExitToHomeAnimation(ctx);
+ if (mTaskStackView != null) {
+ mTaskStackView.startExitToHomeAnimation(ctx);
}
ctx.postAnimationTrigger.decrement();
@@ -329,31 +278,19 @@ 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(width, height, mConfig.systemInsets.top, searchBarSpaceBounds);
+ mConfig.getSearchBarBounds(new Rect(0, 0, width, height), mConfig.systemInsets.top,
+ searchBarSpaceBounds);
mSearchBar.measure(
MeasureSpec.makeMeasureSpec(searchBarSpaceBounds.width(), MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(searchBarSpaceBounds.height(), MeasureSpec.EXACTLY));
}
Rect taskStackBounds = new Rect();
- mConfig.getAvailableTaskStackBounds(width, height, mConfig.systemInsets.top,
+ mConfig.getAvailableTaskStackBounds(new Rect(0, 0, width, height), mConfig.systemInsets.top,
mConfig.systemInsets.right, searchBarSpaceBounds, taskStackBounds);
-
- // Measure each TaskStackView with the full width and height of the window since the
- // transition view is a child of that stack view
- List<TaskStackView> stackViews = getTaskStackViews();
- List<Rect> stackViewsBounds = mLayoutAlgorithm.computeStackRects(stackViews,
- taskStackBounds);
- int stackCount = stackViews.size();
- for (int i = 0; i < stackCount; i++) {
- TaskStackView stackView = stackViews.get(i);
- if (stackView.getVisibility() != GONE) {
- // We are going to measure the TaskStackView with the whole RecentsView dimensions,
- // but the actual stack is going to be inset to the bounds calculated by the layout
- // algorithm
- stackView.setStackInsetRect(stackViewsBounds.get(i));
- stackView.measure(widthMeasureSpec, heightMeasureSpec);
- }
+ if (mTaskStackView != null && mTaskStackView.getVisibility() != GONE) {
+ mTaskStackView.setTaskStackBounds(taskStackBounds);
+ mTaskStackView.measure(widthMeasureSpec, heightMeasureSpec);
}
setMeasuredDimension(width, height);
@@ -365,24 +302,17 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
// Get the search bar bounds so that we lay it out
+ Rect measuredRect = new Rect(0, 0, getMeasuredWidth(), getMeasuredHeight());
+ Rect searchBarSpaceBounds = new Rect();
if (mSearchBar != null) {
- Rect searchBarSpaceBounds = new Rect();
- mConfig.getSearchBarBounds(getMeasuredWidth(), getMeasuredHeight(),
+ mConfig.getSearchBarBounds(measuredRect,
mConfig.systemInsets.top, searchBarSpaceBounds);
mSearchBar.layout(searchBarSpaceBounds.left, searchBarSpaceBounds.top,
searchBarSpaceBounds.right, searchBarSpaceBounds.bottom);
}
- // Layout each TaskStackView with the full width and height of the window since the
- // transition view is a child of that stack view
- List<TaskStackView> stackViews = getTaskStackViews();
- int stackCount = stackViews.size();
- for (int i = 0; i < stackCount; i++) {
- TaskStackView stackView = stackViews.get(i);
- if (stackView.getVisibility() != GONE) {
- stackView.layout(left, top, left + stackView.getMeasuredWidth(),
- top + stackView.getMeasuredHeight());
- }
+ if (mTaskStackView != null && mTaskStackView.getVisibility() != GONE) {
+ mTaskStackView.layout(left, top, left + getMeasuredWidth(), top + getMeasuredHeight());
}
}
@@ -397,29 +327,24 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
/** Notifies each task view of the user interaction. */
public void onUserInteraction() {
// Get the first stack view
- List<TaskStackView> stackViews = getTaskStackViews();
- int stackCount = stackViews.size();
- for (int i = 0; i < stackCount; i++) {
- TaskStackView stackView = stackViews.get(i);
- stackView.onUserInteraction();
+ if (mTaskStackView != null) {
+ mTaskStackView.onUserInteraction();
}
}
/** Focuses the next task in the first stack view */
public void focusNextTask(boolean forward) {
// Get the first stack view
- List<TaskStackView> stackViews = getTaskStackViews();
- if (!stackViews.isEmpty()) {
- stackViews.get(0).focusNextTask(forward, true);
+ if (mTaskStackView != null) {
+ mTaskStackView.focusNextTask(forward, true);
}
}
/** Dismisses the focused task. */
public void dismissFocusedTask() {
// Get the first stack view
- List<TaskStackView> stackViews = getTaskStackViews();
- if (!stackViews.isEmpty()) {
- stackViews.get(0).dismissFocusedTask();
+ if (mTaskStackView != null) {
+ mTaskStackView.dismissFocusedTask();
}
}
@@ -442,9 +367,8 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
}
public void disableLayersForOneFrame() {
- List<TaskStackView> stackViews = getTaskStackViews();
- for (int i = 0; i < stackViews.size(); i++) {
- stackViews.get(i).disableLayersForOneFrame();
+ if (mTaskStackView != null) {
+ mTaskStackView.disableLayersForOneFrame();
}
}
@@ -655,7 +579,7 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
}
postDrawHeaderThumbnailTransitionRunnable(stackView, tv, offsetX, offsetY, stackScroll,
animStartedListener);
- if (mConfig.multiStackEnabled) {
+ if (mConfig.multiWindowEnabled) {
opts = ActivityOptions.makeCustomAnimation(sourceView.getContext(),
R.anim.recents_from_unknown_enter,
R.anim.recents_from_unknown_exit,
@@ -670,7 +594,7 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
opts = ActivityOptions.makeBasic();
}
if (boundsValid) {
- opts.setBounds(bounds);
+ opts.setBounds(bounds.isEmpty() ? null : bounds);
}
final ActivityOptions launchOpts = opts;
final boolean screenPinningRequested = (animStartedListener == null) && lockToTask;
@@ -767,11 +691,8 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
/** Final callback after Recents is finally hidden. */
public void onRecentsHidden() {
// Notify each task stack view
- List<TaskStackView> stackViews = getTaskStackViews();
- int stackCount = stackViews.size();
- for (int i = 0; i < stackCount; i++) {
- TaskStackView stackView = stackViews.get(i);
- stackView.onRecentsHidden();
+ if (mTaskStackView != null) {
+ mTaskStackView.onRecentsHidden();
}
}
@@ -815,11 +736,8 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
@Override
public void onPackagesChanged(RecentsPackageMonitor monitor, String packageName, int userId) {
// Propagate this event down to each task stack view
- List<TaskStackView> stackViews = getTaskStackViews();
- int stackCount = stackViews.size();
- for (int i = 0; i < stackCount; i++) {
- TaskStackView stackView = stackViews.get(i);
- stackView.onPackagesChanged(monitor, packageName, userId);
+ if (mTaskStackView != null) {
+ mTaskStackView.onPackagesChanged(monitor, packageName, userId);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewLayoutAlgorithm.java
deleted file mode 100644
index eea273c1242c..000000000000
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewLayoutAlgorithm.java
+++ /dev/null
@@ -1,59 +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.systemui.recents.views;
-
-import android.graphics.Rect;
-import com.android.systemui.recents.RecentsConfiguration;
-import com.android.systemui.recents.model.TaskStack;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/* The layout logic for the RecentsView. */
-public class RecentsViewLayoutAlgorithm {
-
- RecentsConfiguration mConfig;
-
- public RecentsViewLayoutAlgorithm(RecentsConfiguration config) {
- mConfig = config;
- }
-
- /** Return the relative coordinate given coordinates in another size. */
- private int getRelativeCoordinate(int availableOffset, int availableSize, int otherCoord, int otherSize) {
- float relPos = (float) otherCoord / otherSize;
- return availableOffset + (int) (relPos * availableSize);
- }
-
- /**
- * Computes and returns the bounds that each of the stack views should take up.
- */
- List<Rect> computeStackRects(List<TaskStackView> stackViews, Rect availableBounds) {
- ArrayList<Rect> bounds = new ArrayList<Rect>(stackViews.size());
- int stackViewsCount = stackViews.size();
- for (int i = 0; i < stackViewsCount; i++) {
- TaskStack stack = stackViews.get(i).getStack();
- Rect sb = stack.stackBounds;
- Rect db = stack.displayBounds;
- Rect ab = availableBounds;
- bounds.add(new Rect(getRelativeCoordinate(ab.left, ab.width(), sb.left, db.width()),
- getRelativeCoordinate(ab.top, ab.height(), sb.top, db.height()),
- getRelativeCoordinate(ab.left, ab.width(), sb.right, db.width()),
- getRelativeCoordinate(ab.top, ab.height(), sb.bottom, db.height())));
- }
- return bounds;
- }
-}
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 4e82c8a3e44c..4db8b3708bf3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -79,8 +79,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
ViewPool<TaskView, Task> mViewPool;
ArrayList<TaskViewTransform> mCurrentTaskTransforms = new ArrayList<TaskViewTransform>();
DozeTrigger mUIDozeTrigger;
- DebugOverlayView mDebugOverlay;
- Rect mTaskStackBounds = new Rect();
DismissView mDismissAllButton;
boolean mDismissAllButtonAnimating;
int mFocusedTaskIndex = -1;
@@ -93,6 +91,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
boolean mStartEnterAnimationRequestedAfterLayout;
boolean mStartEnterAnimationCompleted;
ViewAnimation.TaskViewEnterContext mStartEnterAnimationContext;
+ Rect mTaskStackBounds = new Rect();
int[] mTmpVisibleRange = new int[2];
float[] mTmpCoord = new float[2];
Matrix mTmpMatrix = new Matrix();
@@ -161,11 +160,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
return mStack;
}
- /** Sets the debug overlay */
- public void setDebugOverlay(DebugOverlayView overlay) {
- mDebugOverlay = overlay;
- }
-
/** Updates the list of task views */
void updateTaskViewsList() {
mTaskViews.clear();
@@ -334,9 +328,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
int[] visibleRange = mTmpVisibleRange;
boolean isValidVisibleRange = updateStackTransforms(mCurrentTaskTransforms, tasks,
stackScroll, visibleRange, false);
- if (mDebugOverlay != null) {
- mDebugOverlay.setText("vis[" + visibleRange[1] + "-" + visibleRange[0] + "]");
- }
// Inflate and add the dismiss button if necessary
if (Constants.DebugFlags.App.EnableDismissAll && mDismissAllButton == null) {
@@ -477,11 +468,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
mStackViewsClipDirty = false;
}
- /** The stack insets to apply to the stack contents */
- public void setStackInsetRect(Rect r) {
- mTaskStackBounds.set(r);
- }
-
/** Updates the min and max virtual scroll bounds */
void updateMinMaxScroll(boolean boundScrollToNewMinMax, boolean launchedWithAltTab,
boolean launchedFromHome) {
@@ -692,11 +678,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
return mTouchHandler.onGenericMotionEvent(ev);
}
- /** Returns the region that touch gestures can be started in. */
- Rect getTouchableRegion() {
- return mTaskStackBounds;
- }
-
@Override
public void computeScroll() {
mStackScroller.computeScroll();
@@ -736,6 +717,10 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
return mLayoutAlgorithm.computeStackVisibilityReport(mStack.getTasks());
}
+ public void setTaskStackBounds(Rect taskStackBounds) {
+ mTaskStackBounds.set(taskStackBounds);
+ }
+
/**
* This is called with the full window width and height to allow stack view children to
* perform the full screen transition down.
@@ -746,9 +731,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
int height = MeasureSpec.getSize(heightMeasureSpec);
// Compute our stack/task rects
- Rect taskStackBounds = new Rect(mTaskStackBounds);
- taskStackBounds.bottom -= mConfig.systemInsets.bottom;
- computeRects(width, height, taskStackBounds, mConfig.launchedWithAltTab,
+ computeRects(width, height, mTaskStackBounds, mConfig.launchedWithAltTab,
mConfig.launchedFromHome);
// If this is the first layout, then scroll to the front of the stack and synchronize the
@@ -875,7 +858,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
}
// Start dozing
- if (!mConfig.multiStackEnabled) {
+ if (!mConfig.multiWindowEnabled) {
mUIDozeTrigger.startDozing();
}
}
@@ -1299,7 +1282,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.multiStackEnabled || mUIDozeTrigger.hasTriggered()) {
+ if (mConfig.multiWindowEnabled || mUIDozeTrigger.hasTriggered()) {
tv.setNoUserInteractionState();
}
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 2e0b80a9a512..7d079d90fee5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
@@ -128,16 +128,6 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
return false;
}
- int action = ev.getAction();
- if (mConfig.multiStackEnabled) {
- // Check if we are within the bounds of the stack view contents
- if ((action & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_DOWN) {
- if (!mSv.getTouchableRegion().contains((int) ev.getX(), (int) ev.getY())) {
- return false;
- }
- }
- }
-
// Pass through to swipe helper if we are swiping
mInterceptedBySwipeHelper = mSwipeHelper.onInterceptTouchEvent(ev);
if (mInterceptedBySwipeHelper) {
@@ -146,6 +136,7 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
boolean wasScrolling = mScroller.isScrolling() ||
(mScroller.mScrollAnimator != null && mScroller.mScrollAnimator.isRunning());
+ int action = ev.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: {
// Save the touch down info
@@ -212,16 +203,6 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
return false;
}
- int action = ev.getAction();
- if (mConfig.multiStackEnabled) {
- // Check if we are within the bounds of the stack view contents
- if ((action & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_DOWN) {
- if (!mSv.getTouchableRegion().contains((int) ev.getX(), (int) ev.getY())) {
- return false;
- }
- }
- }
-
// Pass through to swipe helper if we are swiping
if (mInterceptedBySwipeHelper && mSwipeHelper.onTouchEvent(ev)) {
return true;
@@ -230,6 +211,7 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
// Update the velocity tracker
initVelocityTrackerIfNotExists();
+ int action = ev.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: {
// Save the touch down info
@@ -372,7 +354,7 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
// Shift the tap position toward the center of the task stack and check to see if it would
// have hit a view. The user might have tried to tap on a task and missed slightly.
int shiftedX = x;
- if (x > mSv.getTouchableRegion().centerX()) {
+ if (x > (mSv.getRight() - mSv.getLeft()) / 2) {
shiftedX -= mWindowTouchSlop;
} else {
shiftedX += mWindowTouchSlop;
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 cbfe8427e256..373fe7b60fd6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -682,7 +682,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
mHeaderView.mApplicationIcon.setOnClickListener(this);
}
mHeaderView.mDismissButton.setOnClickListener(this);
- if (mConfig.multiStackEnabled) {
+ if (mConfig.multiWindowEnabled) {
mHeaderView.mMoveTaskButton.setOnClickListener(this);
}
mActionButtonView.setOnClickListener(this);
@@ -701,7 +701,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
// Unbind any listeners
mHeaderView.mApplicationIcon.setOnClickListener(null);
mHeaderView.mDismissButton.setOnClickListener(null);
- if (mConfig.multiStackEnabled) {
+ if (mConfig.multiWindowEnabled) {
mHeaderView.mMoveTaskButton.setOnClickListener(null);
}
mActionButtonView.setOnClickListener(null);
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 353bcbe640f0..3e9410e1348a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -215,8 +215,8 @@ public class TaskViewHeader extends FrameLayout {
mLightDismissDrawable : mDarkDismissDrawable);
mDismissButton.setContentDescription(String.format(mDismissContentDescription,
t.contentDescription));
- mMoveTaskButton.setVisibility((mConfig.multiStackEnabled) ? View.VISIBLE : View.INVISIBLE);
- if (mConfig.multiStackEnabled) {
+ mMoveTaskButton.setVisibility((mConfig.multiWindowEnabled) ? View.VISIBLE : View.INVISIBLE);
+ if (mConfig.multiWindowEnabled) {
updateResizeTaskBarIcon(t);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index c1dfec3f954b..2e3e00c1a4cf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -34,7 +34,7 @@ import android.view.animation.LinearInterpolator;
import android.view.animation.PathInterpolator;
import com.android.systemui.R;
-import com.android.systemui.analytics.LockedPhoneAnalytics;
+import com.android.systemui.classifier.FalsingManager;
/**
* Base class for both {@link ExpandableNotificationRow} and {@link NotificationOverflowContainer}
@@ -129,7 +129,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
private final int mNormalColor;
private final int mLowPriorityColor;
private boolean mIsBelowSpeedBump;
- private LockedPhoneAnalytics mLockedPhoneAnalytics;
+ private FalsingManager mFalsingManager;
public ActivatableNotificationView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -153,7 +153,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
R.color.notification_ripple_color_low_priority);
mNormalRippleColor = context.getColor(
R.color.notification_ripple_untinted_color);
- mLockedPhoneAnalytics = LockedPhoneAnalytics.getInstance(context);
+ mFalsingManager = FalsingManager.getInstance(context);
}
@Override
@@ -222,7 +222,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
makeActive();
postDelayed(mTapTimeoutRunnable, DOUBLETAP_TIMEOUT_MS);
} else {
- mLockedPhoneAnalytics.onNotificationDoubleTap();
+ mFalsingManager.onNotificationDoubleTap();
boolean performed = performClick();
if (performed) {
removeCallbacks(mTapTimeoutRunnable);
@@ -242,7 +242,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
}
private void makeActive() {
- mLockedPhoneAnalytics.onNotificationActive();
+ mFalsingManager.onNotificationActive();
startActivateAnimation(false /* reverse */);
mActivated = true;
if (mOnActivatedListener != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 2c964be44cac..e7a3c8a3fe72 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -115,8 +115,7 @@ import static com.android.keyguard.KeyguardHostView.OnDismissAction;
public abstract class BaseStatusBar extends SystemUI implements
CommandQueue.Callbacks, ActivatableNotificationView.OnActivatedListener,
- RecentsComponent.Callbacks, ExpandableNotificationRow.ExpansionLogger,
- NotificationData.Environment {
+ ExpandableNotificationRow.ExpansionLogger, NotificationData.Environment {
public static final String TAG = "StatusBar";
public static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
public static final boolean MULTIUSER_DEBUG = false;
@@ -577,7 +576,6 @@ public abstract class BaseStatusBar extends SystemUI implements
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
mRecents = getComponent(Recents.class);
- mRecents.setCallback(this);
final Configuration currentConfig = mContext.getResources().getConfiguration();
mLocale = currentConfig.locale;
@@ -1174,11 +1172,6 @@ public abstract class BaseStatusBar extends SystemUI implements
}
}
- @Override
- public void onVisibilityChanged(boolean visible) {
- // Do nothing
- }
-
/**
* If there is an active heads-up notification and it has a fullscreen intent, fire it now.
*/
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 e2304c100517..687f6c1b0922 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
@@ -29,7 +29,7 @@ import android.view.animation.Interpolator;
import com.android.systemui.ExpandHelper;
import com.android.systemui.Gefingerpoken;
import com.android.systemui.R;
-import com.android.systemui.analytics.LockedPhoneAnalytics;
+import com.android.systemui.classifier.FalsingManager;
/**
* A utility class to enable the downward swipe on the lockscreen to go to the full shade and expand
@@ -55,7 +55,7 @@ public class DragDownHelper implements Gefingerpoken {
private ExpandableView mStartingChild;
private Interpolator mInterpolator;
private float mLastHeight;
- private LockedPhoneAnalytics mLockedPhoneAnalytics;
+ private FalsingManager mFalsingManager;
public DragDownHelper(Context context, View host, ExpandHelper.Callback callback,
DragDownCallback dragDownCallback) {
@@ -67,7 +67,7 @@ public class DragDownHelper implements Gefingerpoken {
mCallback = callback;
mDragDownCallback = dragDownCallback;
mHost = host;
- mLockedPhoneAnalytics = LockedPhoneAnalytics.getInstance(context);
+ mFalsingManager = FalsingManager.getInstance(context);
}
@Override
@@ -87,7 +87,7 @@ public class DragDownHelper implements Gefingerpoken {
case MotionEvent.ACTION_MOVE:
final float h = y - mInitialTouchY;
if (h > mTouchSlop && h > Math.abs(x - mInitialTouchX)) {
- mLockedPhoneAnalytics.onNotificatonStartDraggingDown();
+ mFalsingManager.onNotificatonStartDraggingDown();
mDraggingDown = true;
captureStartingChild(mInitialTouchX, mInitialTouchY);
mInitialTouchY = y;
@@ -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);
@@ -205,7 +212,7 @@ public class DragDownHelper implements Gefingerpoken {
}
private void stopDragging() {
- mLockedPhoneAnalytics.onNotificatonStopDraggingDown();
+ mFalsingManager.onNotificatonStopDraggingDown();
if (mStartingChild != null) {
cancelExpansion(mStartingChild);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 564a60aaeb39..210be9fe3505 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -24,7 +24,6 @@ import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
-import android.graphics.drawable.RippleDrawable;
import android.service.notification.StatusBarNotification;
import android.util.AttributeSet;
import android.view.MotionEvent;
@@ -35,7 +34,7 @@ import android.view.animation.LinearInterpolator;
import android.widget.ImageView;
import com.android.systemui.R;
-import com.android.systemui.analytics.LockedPhoneAnalytics;
+import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.PhoneStatusBar;
import com.android.systemui.statusbar.stack.NotificationChildrenContainer;
@@ -111,7 +110,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
!mChildrenExpanded);
}
};
- private LockedPhoneAnalytics mLockedPhoneAnalytics;
+ private FalsingManager mFalsingManager;
private boolean mJustClicked;
@@ -327,7 +326,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
public ExpandableNotificationRow(Context context, AttributeSet attrs) {
super(context, attrs);
- mLockedPhoneAnalytics = LockedPhoneAnalytics.getInstance(context);
+ mFalsingManager = FalsingManager.getInstance(context);
}
/**
@@ -515,7 +514,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
* @param userExpanded whether the user wants this notification to be expanded
*/
public void setUserExpanded(boolean userExpanded) {
- mLockedPhoneAnalytics.setNotificationExpanded();
+ mFalsingManager.setNotificationExpanded();
if (userExpanded && !mExpandable) return;
final boolean wasExpanded = isExpanded();
mHasUserChangedExpansion = true;
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/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index 5a2fa3bad127..1d890d0dde6c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -33,7 +33,7 @@ public class DozeParameters {
private static final String TAG = "DozeParameters";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
- private static final int MAX_DURATION = 10 * 1000;
+ private static final int MAX_DURATION = 60 * 1000;
private final Context mContext;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
index 84082dbe0d12..29129638fc6c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
@@ -93,6 +93,8 @@ public class FingerprintUnlockController extends KeyguardUpdateMonitorCallback {
private KeyguardViewMediator mKeyguardViewMediator;
private ScrimController mScrimController;
private PhoneStatusBar mPhoneStatusBar;
+ private boolean mGoingToSleep;
+ private int mPendingAuthenticatedUserId = -1;
public FingerprintUnlockController(Context context,
StatusBarWindowManager statusBarWindowManager,
@@ -161,6 +163,10 @@ public class FingerprintUnlockController extends KeyguardUpdateMonitorCallback {
@Override
public void onFingerprintAuthenticated(int userId) {
+ if (mUpdateMonitor.isGoingToSleep()) {
+ mPendingAuthenticatedUserId = userId;
+ return;
+ }
boolean wasDeviceInteractive = mUpdateMonitor.isDeviceInteractive();
mMode = calculateMode();
if (!wasDeviceInteractive) {
@@ -205,6 +211,26 @@ public class FingerprintUnlockController extends KeyguardUpdateMonitorCallback {
mPhoneStatusBar.notifyFpAuthModeChanged();
}
+ @Override
+ public void onStartedGoingToSleep(int why) {
+ mPendingAuthenticatedUserId = -1;
+ }
+
+ @Override
+ public void onFinishedGoingToSleep(int why) {
+ if (mPendingAuthenticatedUserId != -1) {
+
+ // Post this to make sure it's executed after the device is fully locked.
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ onFingerprintAuthenticated(mPendingAuthenticatedUserId);
+ }
+ });
+ }
+ mPendingAuthenticatedUserId = -1;
+ }
+
public int getMode() {
return mMode;
}
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/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index cbd23bb90ac0..99436a19333d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -31,7 +31,7 @@ import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.keyguard.R;
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.DejankUtils;
-import com.android.systemui.analytics.LockedPhoneAnalytics;
+import com.android.systemui.classifier.FalsingManager;
import static com.android.keyguard.KeyguardHostView.OnDismissAction;
import static com.android.keyguard.KeyguardSecurityModel.SecurityMode;
@@ -50,7 +50,7 @@ public class KeyguardBouncer {
private ViewGroup mRoot;
private boolean mShowingSoon;
private int mBouncerPromptReason;
- private LockedPhoneAnalytics mLockedPhoneAnalytics;
+ private FalsingManager mFalsingManager;
private KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
new KeyguardUpdateMonitorCallback() {
@Override
@@ -68,11 +68,11 @@ public class KeyguardBouncer {
mContainer = container;
mWindowManager = windowManager;
KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateMonitorCallback);
- mLockedPhoneAnalytics = LockedPhoneAnalytics.getInstance(mContext);
+ mFalsingManager = FalsingManager.getInstance(mContext);
}
public void show(boolean resetSecuritySelection) {
- mLockedPhoneAnalytics.onBouncerShown();
+ mFalsingManager.onBouncerShown();
ensureView();
if (resetSecuritySelection) {
// showPrimarySecurityScreen() updates the current security method. This is needed in
@@ -132,7 +132,7 @@ public class KeyguardBouncer {
}
public void hide(boolean destroyView) {
- mLockedPhoneAnalytics.onBouncerHidden();
+ mFalsingManager.onBouncerHidden();
cancelShowRunnable();
if (mKeyguardView != null) {
mKeyguardView.cancelDismissAction();
@@ -162,7 +162,7 @@ public class KeyguardBouncer {
public void reset() {
cancelShowRunnable();
inflateView();
- mLockedPhoneAnalytics.onBouncerHidden();
+ mFalsingManager.onBouncerHidden();
}
public void onScreenTurnedOff() {
@@ -250,7 +250,7 @@ public class KeyguardBouncer {
// We need to show it in case it is secure. If not, it will get dismissed in any case.
mRoot.setVisibility(View.VISIBLE);
- mLockedPhoneAnalytics.onBouncerShown();
+ mFalsingManager.onBouncerShown();
mKeyguardView.requestFocus();
mKeyguardView.onResume();
return true;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarApps.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarApps.java
index 5201f35fa224..364e884e816e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarApps.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarApps.java
@@ -31,7 +31,6 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.PixelFormat;
@@ -46,6 +45,7 @@ import android.view.DragEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
+import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
@@ -65,8 +65,11 @@ import java.util.List;
* to the launcher hotseat. Clicking an icon launches or activates the associated activity. A long
* click will trigger a drag to allow the icons to be reordered. As an icon is dragged the other
* icons shift to make space for it to be dropped. These layout changes are animated.
+ * Navigation bar contains both pinned and unpinned apps: pinned in the left part, unpinned in the
+ * right part, with no separator in between.
*/
-class NavigationBarApps extends LinearLayout {
+class NavigationBarApps extends LinearLayout
+ implements NavigationBarAppsModel.OnAppsChangedListener {
public final static boolean DEBUG = false;
private final static String TAG = "NavigationBarApps";
@@ -117,11 +120,20 @@ class NavigationBarApps extends LinearLayout {
// has a child that will be moved to make the menu to appear where we need it.
private final ViewGroup mPopupAnchor;
private final PopupMenu mPopupMenu;
+
+ /**
+ * True if popup menu code is busy with a popup operation.
+ * Attempting to show a popup menu or to add menu items while it's returning true will
+ * corrupt/crash the app.
+ */
+ private boolean mIsPopupInUse = false;
private final int [] mClickedIconLocation = new int[2];
public NavigationBarApps(Context context, AttributeSet attrs) {
super(context, attrs);
- sAppsModel = new NavigationBarAppsModel(context);
+ if (sAppsModel == null) {
+ sAppsModel = new NavigationBarAppsModel(context);
+ }
mPackageManager = context.getPackageManager();
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
@@ -234,7 +246,7 @@ class NavigationBarApps extends LinearLayout {
ComponentName appComponentName = appInfo.getComponentName();
if (!appComponentName.getPackageName().equals(packageName)) continue;
- if (sAppsModel.buildAppLaunchIntent(appInfo) != null) {
+ if (sAppsModel.resolveApp(appInfo) != null) {
continue;
}
@@ -275,6 +287,7 @@ class NavigationBarApps extends LinearLayout {
mContext.registerReceiver(mBroadcastReceiver, filter);
mAppPackageMonitor.register(mContext, null, UserHandle.ALL, true);
+ sAppsModel.addOnAppsChangedListener(this);
}
@Override
@@ -282,18 +295,35 @@ class NavigationBarApps extends LinearLayout {
super.onDetachedFromWindow();
mContext.unregisterReceiver(mBroadcastReceiver);
mAppPackageMonitor.unregister();
+ sAppsModel.removeOnAppsChangedListener(this);
+ }
+
+ @Override
+ protected void onVisibilityChanged(View changedView, int visibility) {
+ super.onVisibilityChanged(changedView, visibility);
+ if (mIsPopupInUse && !isShown()) {
+ // Hide the popup if current view became invisible.
+ shutdownPopupMenu();
+ }
}
private void addAppButton(AppButtonData appButtonData) {
- ImageView button = createAppButton(appButtonData);
+ ImageView button = createAppButton();
+ updateApp(button, appButtonData);
addView(button);
+ }
- AppInfo app = appButtonData.appInfo;
- CharSequence appLabel = getAppLabel(mPackageManager, app.getComponentName());
- button.setContentDescription(appLabel);
-
- // Load the icon asynchronously.
- new GetActivityIconTask(mPackageManager, button).execute(appButtonData);
+ private List<AppInfo> getPinnedApps() {
+ List<AppInfo> apps = new ArrayList<AppInfo>();
+ int childCount = getChildCount();
+ for (int i = 0; i != childCount; ++i) {
+ View child = getChildAt(i);
+ AppButtonData appButtonData = (AppButtonData)child.getTag();
+ if (appButtonData == null) continue; // Skip the drag placeholder.
+ if(!appButtonData.pinned) continue;
+ apps.add(appButtonData.appInfo);
+ }
+ return apps;
}
/**
@@ -316,30 +346,21 @@ class NavigationBarApps extends LinearLayout {
* Saves pinned apps stored in app icons into the data model.
*/
private void savePinnedApps() {
- List<AppInfo> apps = new ArrayList<AppInfo>();
- int childCount = getChildCount();
- for (int i = 0; i != childCount; ++i) {
- View child = getChildAt(i);
- AppButtonData appButtonData = (AppButtonData)child.getTag();
- if (appButtonData == null) continue; // Skip the drag placeholder.
- if(!appButtonData.pinned) continue;
- apps.add(appButtonData.appInfo);
- }
- sAppsModel.setApps(apps);
+ sAppsModel.setApps(getPinnedApps());
}
/**
* Creates a new ImageView for an app, inflated from R.layout.navigation_bar_app_item.
*/
- private ImageView createAppButton(AppButtonData appButtonData) {
+ private ImageView createAppButton() {
ImageView button = (ImageView) mLayoutInflater.inflate(
R.layout.navigation_bar_app_item, this, false /* attachToRoot */);
+ button.setOnHoverListener(new AppHoverListener());
button.setOnClickListener(new AppClickListener());
button.setOnContextClickListener(new AppContextClickListener());
// TODO: Ripple effect. Use either KeyButtonRipple or the default ripple background.
button.setOnLongClickListener(new AppLongClickListener());
button.setOnDragListener(new AppIconDragListener());
- button.setTag(appButtonData);
return button;
}
@@ -358,17 +379,12 @@ class NavigationBarApps extends LinearLayout {
* TODO: Cache the labels, perhaps in an LruCache.
*/
@Nullable
- static CharSequence getAppLabel(PackageManager packageManager,
- ComponentName activityName) {
- String packageName = activityName.getPackageName();
- ApplicationInfo info;
- try {
- info = packageManager.getApplicationInfo(packageName, 0x0 /* flags */);
- } catch (PackageManager.NameNotFoundException e) {
- Slog.w(TAG, "Package not found " + packageName);
- return null;
- }
- return packageManager.getApplicationLabel(info);
+ private CharSequence getAppLabel(AppInfo appInfo) {
+ NavigationBarAppsModel.ResolvedApp resolvedApp = sAppsModel.resolveApp(appInfo);
+ if (resolvedApp == null) return null;
+
+ CharSequence unbadgedLabel = resolvedApp.ri.loadLabel(mPackageManager);
+ return mUserManager.getBadgedLabelForUser(unbadgedLabel, appInfo.getUser());
}
/** Helper function to start dragging an app icon (either pinned or recent). */
@@ -455,23 +471,54 @@ class NavigationBarApps extends LinearLayout {
* Creates a blank icon-sized View to create an empty space during a drag.
*/
private ImageView createPlaceholderDragView(int index) {
- ImageView button = createAppButton(null);
+ ImageView button = createAppButton();
addView(button, index);
return button;
}
/**
+ * Returns initial index for a new app that doesn't exist in Shelf.
+ * Such apps get created by dragging them into Shelf from other apps or by dragging from Shelf
+ * and then back, or by removing from shelf as an intermediate step of pinning an app via menu.
+ * @param indexHint Initial proposed position for the item.
+ * @param isAppPinned True if the app being dragged is pinned.
+ */
+ int getNewAppIndex(int indexHint, boolean isAppPinned) {
+ int i;
+ if (isAppPinned) {
+ // For a pinned app, find the rightmost position to the left of the target that has a
+ // pinned app. We'll insert to the right of that position.
+ for (i = indexHint; i > 0; --i) {
+ View v = getChildAt(i - 1);
+ AppButtonData targetButtonData = (AppButtonData) v.getTag();
+ if (targetButtonData.pinned) break;
+ }
+ } else {
+ // For an unpinned app, find the leftmost position to the right of the target that has
+ // an unpinned app. We'll insert to the left of that position.
+ int childCount = getChildCount();
+ for (i = indexHint; i < childCount; ++i) {
+ View v = getChildAt(i);
+ AppButtonData targetButtonData = (AppButtonData) v.getTag();
+ if (!targetButtonData.pinned) break;
+ }
+ }
+ return i;
+ }
+
+ /**
* Handles a drag entering an existing icon. Not implemented in the drag listener because it
* needs to use LinearLayout/ViewGroup methods.
*/
private void onDragEnteredIcon(View target) {
if (DEBUG) Slog.d(TAG, "onDragEntered " + indexOfChild(target));
- // If the drag didn't start from an existing icon, add an invisible placeholder to create
- // empty space for the user to drag into.
+ int targetIndex = indexOfChild(target);
+
+ // If the drag didn't start from an existing shelf icon, add an invisible placeholder to
+ // create empty space for the user to drag into.
if (mDragView == null) {
- int placeholderIndex = indexOfChild(target);
- mDragView = createPlaceholderDragView(placeholderIndex);
+ mDragView = createPlaceholderDragView(getNewAppIndex(targetIndex, true));
return;
}
@@ -481,7 +528,28 @@ class NavigationBarApps extends LinearLayout {
}
// "Move" the dragged app by removing it and adding it back at the target location.
- int targetIndex = indexOfChild(target);
+ AppButtonData targetButtonData = (AppButtonData) target.getTag();
+ int dragViewIndex = indexOfChild(mDragView);
+ AppButtonData dragViewButtonData = (AppButtonData) mDragView.getTag();
+ // Calculating whether the dragged app is pinned. If the app came from outside if the shelf,
+ // in which case dragViewButtonData == null, it's a new app that we'll pin. Otherwise, the
+ // button data is defined, and we look whether that existing app is pinned.
+ boolean isAppPinned = dragViewButtonData == null || dragViewButtonData.pinned;
+
+ if (dragViewIndex == -1) {
+ // Drag view exists, but is not a child, which means that the drag has started at or
+ // already visited shelf, then left it, and now is entering it again.
+ targetIndex = getNewAppIndex(targetIndex, isAppPinned);
+ } else if (dragViewIndex < targetIndex) {
+ // The dragged app is currently at the left of the view where the drag is.
+ // We shouldn't allow moving a pinned app to the right of the unpinned app.
+ if (!targetButtonData.pinned && isAppPinned) return;
+ } else {
+ // The dragged app is currently at the right of the view where the drag is.
+ // We shouldn't allow moving a unpinned app to the left of the pinned app.
+ if (targetButtonData.pinned && !isAppPinned) return;
+ }
+
// This works, but is subtle:
// * If dragViewIndex > targetIndex then the dragged app is moving from right to left and
// the dragged app will be added in front of the target.
@@ -556,7 +624,7 @@ class NavigationBarApps extends LinearLayout {
return null;
}
AppInfo appInfo = new AppInfo(componentName, appUser);
- if (sAppsModel.buildAppLaunchIntent(appInfo) == null) {
+ if (sAppsModel.resolveApp(appInfo) == null) {
return null;
}
return appInfo;
@@ -564,6 +632,9 @@ class NavigationBarApps extends LinearLayout {
/** Updates the app at a given view index. */
private void updateApp(ImageView button, AppButtonData appButtonData) {
+ CharSequence appLabel = getAppLabel(appButtonData.appInfo);
+ button.setContentDescription(appLabel);
+
button.setTag(appButtonData);
new GetActivityIconTask(mPackageManager, button).execute(appButtonData);
}
@@ -615,6 +686,15 @@ class NavigationBarApps extends LinearLayout {
}
/**
+ * Brings the menu popup to closed state.
+ * Can be called at any stage of the asynchronous process of showing a menu.
+ */
+ private void shutdownPopupMenu() {
+ mWindowManager.removeView(mPopupAnchor);
+ mPopupMenu.dismiss();
+ }
+
+ /**
* Shows already prepopulated popup menu using appIcon for anchor location.
*/
private void showPopupMenu(ImageView appIcon) {
@@ -645,14 +725,93 @@ class NavigationBarApps extends LinearLayout {
mPopupMenu.setOnDismissListener(new PopupMenu.OnDismissListener() {
@Override
public void onDismiss(PopupMenu menu) {
+ // FYU: thorough testing for closing menu either by the user or via
+ // shutdownPopupMenu() called at various moments of the menu creation, revealed that
+ // 'onDismiss' is guaranteed to be called after each invocation of showPopupMenu.
mWindowManager.removeView(mPopupAnchor);
anchorButton.removeOnAttachStateChangeListener(onAttachStateChangeListener);
mPopupMenu.setOnDismissListener(null);
mPopupMenu.getMenu().clear();
+ mIsPopupInUse = false;
}
});
mWindowManager.addView(mPopupAnchor, mPopupAnchorLayoutParams);
+ mIsPopupInUse = true;
+ }
+
+ private void activateTask(int taskPersistentId) {
+ // Launch or bring the activity to front.
+ IActivityManager manager = ActivityManagerNative.getDefault();
+ try {
+ manager.startActivityFromRecents(taskPersistentId, null /* options */);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Exception when activating a recent task", e);
+ } catch (IllegalArgumentException e) {
+ Slog.e(TAG, "Exception when activating a recent task", e);
+ }
+ }
+
+ /**
+ * Adds to the popup menu items for activating each of tasks in the specified list.
+ */
+ private void populateLaunchMenu(AppButtonData appButtonData) {
+ Menu menu = mPopupMenu.getMenu();
+ int taskCount = appButtonData.getTaskCount();
+ for (int i = 0; i < taskCount; ++i) {
+ final RecentTaskInfo taskInfo = appButtonData.tasks.get(i);
+ MenuItem item = menu.add(getActivityForTask(taskInfo).flattenToShortString());
+ item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
+ @Override
+ public boolean onMenuItemClick(MenuItem item) {
+ activateTask(taskInfo.persistentId);
+ return true;
+ }
+ });
+ }
+ }
+
+ /**
+ * Shows a task selection menu for clicked or hovered-over apps that have more than 1 running
+ * tasks.
+ */
+ void maybeShowLaunchMenu(ImageView appIcon) {
+ if (mIsPopupInUse) return;
+ AppButtonData appButtonData = (AppButtonData) appIcon.getTag();
+ if (appButtonData.getTaskCount() <= 1) return;
+
+ populateLaunchMenu(appButtonData);
+ showPopupMenu(appIcon);
+ }
+
+ /**
+ * A listener for hovering over an app icon.
+ */
+ private class AppHoverListener implements View.OnHoverListener {
+ private final long DELAY_MILLIS = 1000;
+ private Runnable mShowMenuCallback;
+
+ @Override
+ public boolean onHover(final View v, MotionEvent event) {
+ if (mShowMenuCallback == null) {
+ mShowMenuCallback = new Runnable() {
+ @Override
+ public void run() {
+ maybeShowLaunchMenu((ImageView) v);
+ }
+ };
+ }
+
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_HOVER_ENTER:
+ postDelayed(mShowMenuCallback, DELAY_MILLIS);
+ break;
+ case MotionEvent.ACTION_HOVER_EXIT:
+ removeCallbacks(mShowMenuCallback);
+ break;
+ }
+ return true;
+ }
}
/**
@@ -660,13 +819,15 @@ class NavigationBarApps extends LinearLayout {
*/
private class AppClickListener implements View.OnClickListener {
private void launchApp(AppInfo appInfo, View anchor) {
- Intent launchIntent = sAppsModel.buildAppLaunchIntent(appInfo);
- if (launchIntent == null) {
+ NavigationBarAppsModel.ResolvedApp resolvedApp = sAppsModel.resolveApp(appInfo);
+ if (resolvedApp == null) {
Toast.makeText(
getContext(), R.string.activity_not_found, Toast.LENGTH_SHORT).show();
return;
}
+ Intent launchIntent = resolvedApp.launchIntent;
+
// Play a scale-up animation while launching the activity.
// TODO: Consider playing a different animation, or no animation, if the activity is
// already open in a visible window. In that case we should move the task to front
@@ -682,49 +843,6 @@ class NavigationBarApps extends LinearLayout {
mContext.startActivityAsUser(launchIntent, optsBundle, appInfo.getUser());
}
- private void activateTask(int taskPersistentId) {
- // Launch or bring the activity to front.
- IActivityManager manager = ActivityManagerNative.getDefault();
- try {
- manager.startActivityFromRecents(taskPersistentId, null /* options */);
- } catch (RemoteException e) {
- Slog.e(TAG, "Exception when activating a recent task", e);
- } catch (IllegalArgumentException e) {
- Slog.e(TAG, "Exception when activating a recent task", e);
- }
- }
-
- /**
- * Adds to the popup menu items for activating each of tasks in the specified list.
- */
- void populateLaunchMenu(List<RecentTaskInfo> tasks) {
- Menu menu = mPopupMenu.getMenu();
- int taskCount = tasks.size();
- for (int i = 0; i < taskCount; ++i) {
- final RecentTaskInfo taskInfo = tasks.get(i);
- MenuItem item = menu.add(getActivityForTask(taskInfo).flattenToShortString());
- item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
- @Override
- public boolean onMenuItemClick(MenuItem item) {
- activateTask(taskInfo.persistentId);
- return true;
- }
- });
- }
- }
-
- /**
- * Shows a task selection menu for clicked apps that have more than 1 running tasks.
- */
- void maybeShowLaunchMenu(ImageView appIcon) {
- final AppButtonData appButtonData = (AppButtonData) appIcon.getTag();
-
- if (appButtonData.getTaskCount() <= 1) return;
-
- populateLaunchMenu(appButtonData.tasks);
- showPopupMenu(appIcon);
- }
-
@Override
public void onClick(View v) {
AppButtonData appButtonData = (AppButtonData) v.getTag();
@@ -764,8 +882,11 @@ class NavigationBarApps extends LinearLayout {
@Override
public boolean onMenuItemClick(MenuItem item) {
appButtonData.pinned = false;
- if (appButtonData.isEmpty()) {
- removeView(appIcon);
+ removeView(appIcon);
+ if (!appButtonData.isEmpty()) {
+ // If the app has running tasks, re-add it to the end of shelf
+ // after unpinning.
+ addView(appIcon);
}
updateState(appIcon);
return true;
@@ -776,6 +897,9 @@ class NavigationBarApps extends LinearLayout {
@Override
public boolean onMenuItemClick(MenuItem item) {
appButtonData.pinned = true;
+ removeView(appIcon);
+ // Re-add the pinned icon to the end of the pinned list.
+ addView(appIcon, getNewAppIndex(getChildCount(), true));
updateState(appIcon);
return true;
}
@@ -785,6 +909,7 @@ class NavigationBarApps extends LinearLayout {
@Override
public boolean onContextClick(View v) {
+ if (mIsPopupInUse) return true;
ImageView appIcon = (ImageView) v;
populateContextMenu(appIcon);
showPopupMenu(appIcon);
@@ -945,7 +1070,7 @@ class NavigationBarApps extends LinearLayout {
UserHandle taskUser = new UserHandle(task.userId);
AppInfo appInfo = new AppInfo(componentName, taskUser);
- if (sAppsModel.buildAppLaunchIntent(appInfo) == null) {
+ if (sAppsModel.resolveApp(appInfo) == null) {
// If task's activity is not launcheable, fall back to a launch component of the
// task's package.
ComponentName component = getLaunchComponentForPackage(
@@ -978,4 +1103,11 @@ class NavigationBarApps extends LinearLayout {
});
}
}
+
+ @Override
+ public void onPinnedAppsChanged() {
+ if (getPinnedApps().equals(sAppsModel.getApps())) return;
+ recreatePinnedAppButtons();
+ updateRecentApps();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarAppsModel.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarAppsModel.java
index 832a3e9f38bb..d527f29cc557 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarAppsModel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarAppsModel.java
@@ -44,6 +44,15 @@ import java.util.Set;
* ComponentName.
*/
class NavigationBarAppsModel {
+ public interface OnAppsChangedListener {
+ void onPinnedAppsChanged();
+ }
+
+ public class ResolvedApp {
+ Intent launchIntent;
+ ResolveInfo ri;
+ }
+
private final static String TAG = "NavigationBarAppsModel";
// Default number of apps to load initially.
@@ -79,6 +88,9 @@ class NavigationBarAppsModel {
// Apps are represented as an ordered list of app infos.
private List<AppInfo> mApps = new ArrayList<AppInfo>();
+ private List<OnAppsChangedListener> mOnAppsChangedListeners =
+ new ArrayList<OnAppsChangedListener>();
+
// Id of the current user.
private int mCurrentUserId = -1;
@@ -105,8 +117,8 @@ class NavigationBarAppsModel {
return AppGlobals.getPackageManager();
}
- // Returns a launch intent for a given app info, or null if the app info is unlauncheable.
- public Intent buildAppLaunchIntent(AppInfo appInfo) {
+ // Returns a resolved app info for a given app info, or null if the app info is unlauncheable.
+ public ResolvedApp resolveApp(AppInfo appInfo) {
ComponentName component = appInfo.getComponentName();
int appUserId = appInfo.getUser().getIdentifier();
@@ -153,13 +165,17 @@ class NavigationBarAppsModel {
0 /* flags */, appUserId);
final int size = apps.size();
for (int i = 0; i < size; ++i) {
- ActivityInfo activityInfo = apps.get(i).activityInfo;
+ ResolveInfo ri = apps.get(i);
+ ActivityInfo activityInfo = ri.activityInfo;
if (activityInfo.packageName.equals(component.getPackageName()) &&
activityInfo.name.equals(component.getClassName())) {
// Found an activity with category launcher that matches
// this component so ok to launch.
launchIntent.setComponent(component);
- return launchIntent;
+ ResolvedApp resolvedApp = new ResolvedApp();
+ resolvedApp.launchIntent = launchIntent;
+ resolvedApp.ri = ri;
+ return resolvedApp;
}
}
@@ -167,6 +183,14 @@ class NavigationBarAppsModel {
return null;
}
+ public void addOnAppsChangedListener(OnAppsChangedListener listener) {
+ mOnAppsChangedListeners.add(listener);
+ }
+
+ public void removeOnAppsChangedListener(OnAppsChangedListener listener) {
+ mOnAppsChangedListeners.remove(listener);
+ }
+
/**
* Reinitializes the model for a new user.
*/
@@ -239,6 +263,11 @@ class NavigationBarAppsModel {
public void setApps(List<AppInfo> apps) {
mApps = apps;
savePrefs();
+
+ int size = mOnAppsChangedListeners.size();
+ for (int i = 0; i < size; ++i) {
+ mOnAppsChangedListeners.get(i).onPinnedAppsChanged();
+ }
}
/** Saves the current model to disk. */
@@ -280,7 +309,7 @@ class NavigationBarAppsModel {
return null;
}
AppInfo appInfo = new AppInfo(componentName, appUser);
- if (buildAppLaunchIntent(appInfo) == null) {
+ if (resolveApp(appInfo) == null) {
return null;
}
return appInfo;
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 f47ec20e4246..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,7 +22,7 @@ import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.app.ActivityManager;
-import android.app.ActivityManager.RunningTaskInfo;
+import android.app.StatusBarManager;
import android.content.Context;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
@@ -50,6 +50,7 @@ import com.android.systemui.DejankUtils;
import com.android.systemui.EventLogConstants;
import com.android.systemui.EventLogTags;
import com.android.systemui.R;
+import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.qs.QSContainer;
import com.android.systemui.qs.QSPanel;
import com.android.systemui.statusbar.ExpandableNotificationRow;
@@ -59,7 +60,6 @@ import com.android.systemui.statusbar.GestureRecorder;
import com.android.systemui.statusbar.KeyguardAffordanceView;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.analytics.LockedPhoneAnalytics;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
@@ -204,7 +204,8 @@ public class NotificationPanelView extends PanelView implements
private boolean mClosingWithAlphaFadeOut;
private boolean mHeadsUpAnimatingAway;
private boolean mLaunchingAffordance;
- private LockedPhoneAnalytics mLockedPhoneAnalytics;
+ private FalsingManager mFalsingManager;
+ private String mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_AFFORDANCE;
private Runnable mHeadsUpExistenceChangedRunnable = new Runnable() {
@Override
@@ -221,7 +222,7 @@ public class NotificationPanelView extends PanelView implements
public NotificationPanelView(Context context, AttributeSet attrs) {
super(context, attrs);
setWillNotDraw(!DEBUG);
- mLockedPhoneAnalytics = LockedPhoneAnalytics.getInstance(context);
+ mFalsingManager = FalsingManager.getInstance(context);
}
public void setStatusBar(PhoneStatusBar bar) {
@@ -481,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();
@@ -693,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()) {
@@ -703,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() {
@@ -813,7 +821,7 @@ public class NotificationPanelView extends PanelView implements
private void handleQsDown(MotionEvent event) {
if (event.getActionMasked() == MotionEvent.ACTION_DOWN
&& shouldQuickSettingsIntercept(event.getX(), event.getY(), -1)) {
- mLockedPhoneAnalytics.onQsDown();
+ mFalsingManager.onQsDown();
mQsTracking = true;
onQsExpansionStarted();
mInitialHeightOnTouch = mQsExpansionHeight;
@@ -981,7 +989,7 @@ public class NotificationPanelView extends PanelView implements
mQsExpanded = expanded;
updateQsState();
requestPanelHeightUpdate();
- mLockedPhoneAnalytics.setQsExpanded(expanded);
+ mFalsingManager.setQsExpanded(expanded);
mNotificationStackScroller.setInterceptDelegateEnabled(expanded);
mStatusBar.setQsExpanded(expanded);
mQsPanel.setExpanded(expanded);
@@ -1308,7 +1316,7 @@ public class NotificationPanelView extends PanelView implements
R.string.accessibility_desc_quick_settings));
mLastAnnouncementWasQuickSettings = true;
}
- if (mQsFullyExpanded && mLockedPhoneAnalytics.shouldEnforceBouncer()) {
+ if (mQsFullyExpanded && mFalsingManager.shouldEnforceBouncer()) {
mStatusBar.executeRunnableDismissingKeyguard(null, null /* cancelAction */,
false /* dismissShade */, true /* afterKeyguardGone */);
}
@@ -1429,7 +1437,7 @@ public class NotificationPanelView extends PanelView implements
}
return;
}
- boolean belowFalsingThreshold = isBelowFalsingThreshold();
+ boolean belowFalsingThreshold = isFalseTouch();
if (belowFalsingThreshold) {
vel = 0;
}
@@ -1839,7 +1847,7 @@ public class NotificationPanelView extends PanelView implements
@Override
protected void onTrackingStarted() {
- mLockedPhoneAnalytics.onTrackingStarted();
+ mFalsingManager.onTrackingStarted();
super.onTrackingStarted();
if (mQsFullyExpanded) {
mQsExpandImmediate = true;
@@ -1853,7 +1861,7 @@ public class NotificationPanelView extends PanelView implements
@Override
protected void onTrackingStopped(boolean expand) {
- mLockedPhoneAnalytics.onTrackingStopped();
+ mFalsingManager.onTrackingStopped();
super.onTrackingStopped(expand);
if (expand) {
mNotificationStackScroller.setOverScrolledPixels(
@@ -1953,8 +1961,8 @@ public class NotificationPanelView extends PanelView implements
EventLogTags.writeSysuiLockscreenGesture(
EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_SWIPE_DIALER, lengthDp, velocityDp);
- mLockedPhoneAnalytics.onLeftAffordanceOn();
- if (mLockedPhoneAnalytics.shouldEnforceBouncer()) {
+ mFalsingManager.onLeftAffordanceOn();
+ if (mFalsingManager.shouldEnforceBouncer()) {
mStatusBar.executeRunnableDismissingKeyguard(new Runnable() {
@Override
public void run() {
@@ -1966,20 +1974,23 @@ public class NotificationPanelView extends PanelView implements
mKeyguardBottomArea.launchLeftAffordance();
}
} else {
- EventLogTags.writeSysuiLockscreenGesture(
- EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_SWIPE_CAMERA, lengthDp, velocityDp);
-
- mLockedPhoneAnalytics.onCameraOn();
- if (mLockedPhoneAnalytics.shouldEnforceBouncer()) {
+ 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();
@@ -2024,7 +2035,7 @@ public class NotificationPanelView extends PanelView implements
@Override
public void onSwipingStarted(boolean rightIcon) {
- mLockedPhoneAnalytics.onAffordanceSwipingStarted(rightIcon);
+ mFalsingManager.onAffordanceSwipingStarted(rightIcon);
boolean camera = getLayoutDirection() == LAYOUT_DIRECTION_RTL ? !rightIcon
: rightIcon;
if (camera) {
@@ -2037,7 +2048,7 @@ public class NotificationPanelView extends PanelView implements
@Override
public void onSwipingAborted() {
- mLockedPhoneAnalytics.onAffordanceSwipingAborted();
+ mFalsingManager.onAffordanceSwipingAborted();
mKeyguardBottomArea.unbindCameraPrewarmService(false /* launched */);
}
@@ -2420,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 9cd6ea3ffd0d..bd16257e6ece 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -35,6 +35,9 @@ import android.widget.FrameLayout;
import com.android.systemui.EventLogConstants;
import com.android.systemui.EventLogTags;
import com.android.systemui.R;
+import com.android.systemui.classifier.Classifier;
+import com.android.systemui.classifier.FalsingManager;
+import com.android.systemui.classifier.HumanInteractionClassifier;
import com.android.systemui.doze.DozeLog;
import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.statusbar.StatusBarState;
@@ -85,6 +88,7 @@ public abstract class PanelView extends FrameLayout {
private ObjectAnimator mPeekAnimator;
private VelocityTrackerInterface mVelocityTracker;
private FlingAnimationUtils mFlingAnimationUtils;
+ private FalsingManager mFalsingManager;
/**
* Whether an instant expand request is currently pending and we are just waiting for layout.
@@ -190,6 +194,7 @@ public abstract class PanelView extends FrameLayout {
mLinearOutSlowInInterpolator =
AnimationUtils.loadInterpolator(context, android.R.interpolator.linear_out_slow_in);
mBounceInterpolator = new BounceInterpolator();
+ mFalsingManager = FalsingManager.getInstance(context);
}
protected void loadDimens() {
@@ -605,6 +610,9 @@ public abstract class PanelView extends FrameLayout {
if (!mStatusBar.isFalsingThresholdNeeded()) {
return false;
}
+ 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 d3af8f03fa73..98f5444b16d8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -108,6 +108,7 @@ import com.android.systemui.EventLogConstants;
import com.android.systemui.EventLogTags;
import com.android.systemui.Prefs;
import com.android.systemui.R;
+import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.doze.DozeHost;
import com.android.systemui.doze.DozeLog;
@@ -131,7 +132,6 @@ import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.SignalClusterView;
import com.android.systemui.statusbar.SpeedBumpView;
import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.analytics.LockedPhoneAnalytics;
import com.android.systemui.statusbar.phone.UnlockMethodCache.OnUnlockMethodChangedListener;
import com.android.systemui.statusbar.policy.AccessibilityController;
import com.android.systemui.statusbar.policy.BatteryController;
@@ -315,6 +315,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
boolean mLeaveOpenOnKeyguardHide;
KeyguardIndicationController mKeyguardIndicationController;
+ // Keyguard is going away soon.
+ private boolean mKeyguardGoingAway;
+ // Keyguard is actually fading away now.
private boolean mKeyguardFadingAway;
private long mKeyguardFadingAwayDelay;
private long mKeyguardFadingAwayDuration;
@@ -488,12 +491,19 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
private boolean mLaunchTransitionFadingAway;
private ExpandableNotificationRow mDraggedDownRow;
private boolean mLaunchCameraOnScreenTurningOn;
+ private boolean mLaunchCameraOnFinishedGoingToSleep;
+ private int mLastCameraLaunchSource;
private PowerManager.WakeLock mGestureWakeLock;
private Vibrator mVibrator;
// Fingerprint (as computed by getLoggingFingerprint() of the last logged state.
private int mLastLoggedStateFingerprint;
+ /**
+ * If set, the device has started going to sleep but isn't fully non-interactive yet.
+ */
+ protected boolean mStartedGoingToSleep;
+
private static final int VISIBLE_LOCATIONS = StackViewState.LOCATION_FIRST_CARD
| StackViewState.LOCATION_MAIN_AREA;
@@ -595,7 +605,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
private HashSet<Entry> mHeadsUpEntriesToRemoveOnSwitch = new HashSet<>();
private RankingMap mLatestRankingMap;
private boolean mNoAnimationOnNextBarModeChange;
- private LockedPhoneAnalytics mLockedPhoneAnalytics;
+ private FalsingManager mFalsingManager;
@Override
public void start() {
@@ -643,7 +653,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
notifyUserAboutHiddenNotifications();
mScreenPinningRequest = new ScreenPinningRequest(mContext);
- mLockedPhoneAnalytics = LockedPhoneAnalytics.getInstance(mContext);
+ mFalsingManager = FalsingManager.getInstance(mContext);
}
// ================================================================================
@@ -3596,6 +3606,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
// Treat Keyguard exit animation as an app transition to achieve nice transition for status
// bar.
+ mKeyguardGoingAway = true;
mIconController.appTransitionPending();
}
@@ -3627,6 +3638,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
*/
public void finishKeyguardFadingAway() {
mKeyguardFadingAway = false;
+ mKeyguardGoingAway = false;
}
public void stopWaitingForKeyguardExit() {
@@ -3800,7 +3812,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
mState = state;
mGroupManager.setStatusBarState(state);
- mLockedPhoneAnalytics.setStatusBarState(state);
+ mFalsingManager.setStatusBarState(state);
mStatusBarWindowManager.setStatusBarState(state);
updateDozing();
}
@@ -3822,7 +3834,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
public void onUnlockHintStarted() {
- mLockedPhoneAnalytics.onUnlockHintStarted();
+ mFalsingManager.onUnlockHintStarted();
mKeyguardIndicationController.showTransientIndication(R.string.keyguard_unlock);
}
@@ -3832,17 +3844,17 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
public void onCameraHintStarted() {
- mLockedPhoneAnalytics.onCameraHintStarted();
+ mFalsingManager.onCameraHintStarted();
mKeyguardIndicationController.showTransientIndication(R.string.camera_hint);
}
public void onVoiceAssistHintStarted() {
- mLockedPhoneAnalytics.onLeftAffordanceHintStarted();
+ mFalsingManager.onLeftAffordanceHintStarted();
mKeyguardIndicationController.showTransientIndication(R.string.voice_hint);
}
public void onPhoneHintStarted() {
- mLockedPhoneAnalytics.onLeftAffordanceHintStarted();
+ mFalsingManager.onLeftAffordanceHintStarted();
mKeyguardIndicationController.showTransientIndication(R.string.phone_hint);
}
@@ -3917,7 +3929,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
row.setUserExpanded(true);
}
boolean fullShadeNeedsBouncer = !userAllowsPrivateNotificationsInPublic(mCurrentUserId)
- || !mShowLockscreenNotifications || mLockedPhoneAnalytics.shouldEnforceBouncer();
+ || !mShowLockscreenNotifications || mFalsingManager.shouldEnforceBouncer();
if (isLockscreenPublicMode() && fullShadeNeedsBouncer) {
mLeaveOpenOnKeyguardHide = true;
showBouncer();
@@ -3958,16 +3970,33 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
disable(mDisabledUnmodified1, mDisabledUnmodified2, true /* animate */);
}
+ public void onStartedGoingToSleep() {
+ mStartedGoingToSleep = true;
+ }
+
public void onFinishedGoingToSleep() {
mNotificationPanel.onAffordanceLaunchEnded();
releaseGestureWakeLock();
mLaunchCameraOnScreenTurningOn = false;
+ mStartedGoingToSleep = false;
mDeviceInteractive = false;
mWakeUpComingFromTouch = false;
mWakeUpTouchLocation = null;
- mLockedPhoneAnalytics.onScreenOff();
+ mFalsingManager.onScreenOff();
mStackScroller.setAnimationsEnabled(false);
updateVisibleToUser();
+ if (mLaunchCameraOnFinishedGoingToSleep) {
+ mLaunchCameraOnFinishedGoingToSleep = false;
+
+ // This gets executed before we will show Keyguard, so post it in order that the state
+ // is correct.
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ onCameraLaunchGestureDetected(mLastCameraLaunchSource);
+ }
+ });
+ }
}
public void onStartedWakingUp() {
@@ -3975,20 +4004,21 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mStackScroller.setAnimationsEnabled(true);
mNotificationPanel.setTouchDisabled(false);
updateVisibleToUser();
- mLockedPhoneAnalytics.onScreenOn();
}
public void onScreenTurningOn() {
mScreenTurningOn = true;
+ mFalsingManager.onScreenTurningOn();
mNotificationPanel.onScreenTurningOn();
if (mLaunchCameraOnScreenTurningOn) {
- mNotificationPanel.launchCamera(false);
+ mNotificationPanel.launchCamera(false, mLastCameraLaunchSource);
mLaunchCameraOnScreenTurningOn = false;
}
}
private void vibrateForCameraGesture() {
- mVibrator.vibrate(750L);
+ // Make sure to pass -1 for repeat so VibratorService doesn't stop us when going to sleep.
+ mVibrator.vibrate(new long[] { 0, 750L }, -1 /* repeat */);
}
public void onScreenTurnedOn() {
@@ -4077,8 +4107,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
super.toggleRecents();
}
- @Override
- public void onVisibilityChanged(boolean visible) {
+ public void updateRecentsVisibility(boolean visible) {
// Update the recents visibility flag
if (visible) {
mSystemUiVisibility |= View.RECENT_APPS_VISIBLE;
@@ -4114,7 +4143,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mWakeUpTouchLocation = new PointF(event.getX(), event.getY());
mNotificationPanel.setTouchDisabled(false);
mStatusBarKeyguardViewManager.notifyDeviceWakeUpRequested();
- mLockedPhoneAnalytics.onScreenOnFromTouch();
+ mFalsingManager.onScreenOnFromTouch();
}
}
@@ -4137,9 +4166,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
public void appTransitionStarting(long startTime, long duration) {
// Use own timings when Keyguard is going away, see keyguardGoingAway and
- // setKeyguardFadingAway. When duration is 0, skip this one because no animation is really
- // playing.
- if (!mKeyguardFadingAway && duration > 0) {
+ // setKeyguardFadingAway.
+ if (!mKeyguardGoingAway) {
mIconController.appTransitionStarting(startTime, duration);
}
if (mIconPolicy != null) {
@@ -4148,7 +4176,12 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
@Override
- public void onCameraLaunchGestureDetected() {
+ public void onCameraLaunchGestureDetected(int source) {
+ mLastCameraLaunchSource = source;
+ if (mStartedGoingToSleep) {
+ mLaunchCameraOnFinishedGoingToSleep = true;
+ return;
+ }
if (!mNotificationPanel.canCameraGestureBeLaunched(
mStatusBarKeyguardViewManager.isShowing() && mExpandedVisible)) {
return;
@@ -4170,7 +4203,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/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index e26f42301830..05f6e57d9199 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -164,6 +164,10 @@ public class StatusBarKeyguardViewManager {
}
}
+ public void onStartedGoingToSleep() {
+ mPhoneStatusBar.onStartedGoingToSleep();
+ }
+
public void onFinishedGoingToSleep() {
mDeviceInteractive = false;
mPhoneStatusBar.onFinishedGoingToSleep();
@@ -462,7 +466,7 @@ public class StatusBarKeyguardViewManager {
KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
if ((showing && !occluded) != (mLastShowing && !mLastOccluded) || mFirstUpdate) {
- updateMonitor.sendKeyguardVisibilityChanged(showing && !occluded);
+ updateMonitor.onKeyguardVisibilityChanged(showing && !occluded);
}
if (bouncerShowing != mLastBouncerShowing || mFirstUpdate) {
updateMonitor.sendKeyguardBouncerChanged(bouncerShowing);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index bbf981f3de4c..cfd33589588c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -36,10 +36,10 @@ import android.view.WindowManagerGlobal;
import android.widget.FrameLayout;
import com.android.systemui.R;
+import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.statusbar.BaseStatusBar;
import com.android.systemui.statusbar.DragDownHelper;
import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.analytics.LockedPhoneAnalytics;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
@@ -56,14 +56,14 @@ public class StatusBarWindowView extends FrameLayout {
private PhoneStatusBar mService;
private final Paint mTransparentSrcPaint = new Paint();
- private LockedPhoneAnalytics mLockedPhoneAnalytics;
+ private FalsingManager mFalsingManager;
public StatusBarWindowView(Context context, AttributeSet attrs) {
super(context, attrs);
setMotionEventSplittingEnabled(false);
mTransparentSrcPaint.setColor(0);
mTransparentSrcPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
- mLockedPhoneAnalytics = LockedPhoneAnalytics.getInstance(context);
+ mFalsingManager = FalsingManager.getInstance(context);
}
@Override
@@ -200,7 +200,7 @@ public class StatusBarWindowView extends FrameLayout {
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
- mLockedPhoneAnalytics.onTouchEvent(ev, getWidth(), getHeight());
+ mFalsingManager.onTouchEvent(ev, getWidth(), getHeight());
if (mBrightnessMirror != null && mBrightnessMirror.getVisibility() == VISIBLE) {
// Disallow new pointers while the brightness mirror is visible. This is so that you
// can't touch anything other than the brightness slider while the mirror is showing
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiIcons.java
index c56646fc7740..374408d3ec7a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiIcons.java
@@ -18,7 +18,7 @@ package com.android.systemui.statusbar.policy;
import com.android.systemui.R;
-class WifiIcons {
+public class WifiIcons {
static final int[][] WIFI_SIGNAL_STRENGTH = {
{ R.drawable.stat_sys_wifi_signal_0,
R.drawable.stat_sys_wifi_signal_1,
@@ -32,7 +32,7 @@ class WifiIcons {
R.drawable.stat_sys_wifi_signal_4_fully }
};
- static final int[][] QS_WIFI_SIGNAL_STRENGTH = {
+ public static final int[][] QS_WIFI_SIGNAL_STRENGTH = {
{ R.drawable.ic_qs_wifi_0,
R.drawable.ic_qs_wifi_1,
R.drawable.ic_qs_wifi_2,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index a1d73d28901d..5e5f8108dfb8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -37,6 +37,7 @@ import android.widget.OverScroller;
import com.android.systemui.ExpandHelper;
import com.android.systemui.R;
import com.android.systemui.SwipeHelper;
+import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.statusbar.ActivatableNotificationView;
import com.android.systemui.statusbar.DismissView;
import com.android.systemui.statusbar.EmptyShadeView;
@@ -47,7 +48,6 @@ import com.android.systemui.statusbar.NotificationOverflowContainer;
import com.android.systemui.statusbar.SpeedBumpView;
import com.android.systemui.statusbar.StackScrollerDecorView;
import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.analytics.LockedPhoneAnalytics;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.PhoneStatusBar;
import com.android.systemui.statusbar.phone.ScrimController;
@@ -232,7 +232,7 @@ public class NotificationStackScrollLayout extends ViewGroup
private boolean mForceNoOverlappingRendering;
private NotificationOverflowContainer mOverflowContainer;
private final ArrayList<Pair<ExpandableNotificationRow, Boolean>> mTmpList = new ArrayList<>();
- private LockedPhoneAnalytics mLockedPhoneAnalytics;
+ private FalsingManager mFalsingManager;
public NotificationStackScrollLayout(Context context) {
this(context, null);
@@ -266,7 +266,7 @@ public class NotificationStackScrollLayout extends ViewGroup
mDebugPaint.setStrokeWidth(2);
mDebugPaint.setStyle(Paint.Style.STROKE);
}
- mLockedPhoneAnalytics = LockedPhoneAnalytics.getInstance(context);
+ mFalsingManager = FalsingManager.getInstance(context);
}
@Override
@@ -599,8 +599,8 @@ public class NotificationStackScrollLayout extends ViewGroup
}
if (DEBUG) Log.v(TAG, "onChildDismissed: " + v);
- mLockedPhoneAnalytics.onNotificationDismissed();
- if (mLockedPhoneAnalytics.shouldEnforceBouncer()) {
+ mFalsingManager.onNotificationDismissed();
+ if (mFalsingManager.shouldEnforceBouncer()) {
mPhoneStatusBar.executeRunnableDismissingKeyguard(null, null /* cancelAction */,
false /* dismissShade */, true /* afterKeyguardGone */);
}
@@ -631,7 +631,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
public void onBeginDrag(View v) {
- mLockedPhoneAnalytics.onNotificatonStartDismissing();
+ mFalsingManager.onNotificatonStartDismissing();
setSwipingInProgress(true);
mAmbientState.onBeginDrag(v);
if (mAnimationsEnabled && (mIsExpanded || !isPinnedHeadsUp(v))) {
@@ -658,7 +658,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
public void onDragCancelled(View v) {
- mLockedPhoneAnalytics.onNotificatonStopDismissing();
+ mFalsingManager.onNotificatonStopDismissing();
setSwipingInProgress(false);
}
@@ -2156,6 +2156,7 @@ public class NotificationStackScrollLayout extends ViewGroup
case MotionEvent.ACTION_DOWN: {
final int y = (int) ev.getY();
+ mScrolledToTopOnFirstDown = isScrolledToTop();
if (getChildAtPosition(ev.getX(), y) == null) {
setIsBeingDragged(false);
recycleVelocityTracker();
@@ -2169,7 +2170,6 @@ public class NotificationStackScrollLayout extends ViewGroup
mLastMotionY = y;
mDownX = (int) ev.getX();
mActivePointerId = ev.getPointerId(0);
- mScrolledToTopOnFirstDown = isScrolledToTop();
initOrResetVelocityTracker();
mVelocityTracker.addMovement(ev);
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/volume/VolumeDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
index b2f527e3bbb4..da19b06d2f40 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
@@ -89,7 +89,6 @@ public class VolumeDialog {
private static final long USER_ATTEMPT_GRACE_PERIOD = 1000;
private static final int WAIT_FOR_RIPPLE = 200;
- private static final int UPDATE_ANIMATION_DURATION = 80;
private final Context mContext;
private final H mHandler = new H();
@@ -353,14 +352,6 @@ public class VolumeDialog {
writer.println(mAccessibility.mFeedbackEnabled);
}
- private static int getImpliedLevel(SeekBar seekBar, int progress) {
- final int m = seekBar.getMax();
- final int n = m / 100 - 1;
- final int level = progress == 0 ? 0
- : progress == m ? (m / 100) : (1 + (int)((progress / (float) m) * n));
- return level;
- }
-
@SuppressLint("InflateParams")
private VolumeRow initRow(final int stream, int iconRes, int iconMuteRes, boolean important) {
final VolumeRow row = new VolumeRow();
@@ -690,7 +681,7 @@ public class VolumeDialog {
: false;
// update slider max
- final int max = ss.levelMax * 100;
+ final int max = ss.levelMax;
if (max != row.slider.getMax()) {
row.slider.setMax(max);
}
@@ -777,8 +768,7 @@ public class VolumeDialog {
if (row.tracking) {
return; // don't update if user is sliding
}
- final int progress = row.slider.getProgress();
- final int level = getImpliedLevel(row.slider, progress);
+ final int level = row.slider.getProgress();
final boolean rowVisible = row.view.getVisibility() == View.VISIBLE;
final boolean inGracePeriod = (SystemClock.uptimeMillis() - row.userAttempt)
< USER_ATTEMPT_GRACE_PERIOD;
@@ -794,33 +784,7 @@ public class VolumeDialog {
return; // don't clamp if visible
}
}
- final int newProgress = vlevel * 100;
- if (progress != newProgress) {
- if (mShowing && rowVisible) {
- // animate!
- if (row.anim != null && row.anim.isRunning()
- && row.animTargetProgress == newProgress) {
- return; // already animating to the target progress
- }
- // start/update animation
- if (row.anim == null) {
- row.anim = ObjectAnimator.ofInt(row.slider, "progress", progress, newProgress);
- row.anim.setInterpolator(new DecelerateInterpolator());
- } else {
- row.anim.cancel();
- row.anim.setIntValues(progress, newProgress);
- }
- row.animTargetProgress = newProgress;
- row.anim.setDuration(UPDATE_ANIMATION_DURATION);
- row.anim.start();
- } else {
- // update slider directly to clamped value
- if (row.anim != null) {
- row.anim.cancel();
- }
- row.slider.setProgress(newProgress);
- }
- }
+ row.slider.setProgress(vlevel, true);
}
private void recheckH(VolumeRow row) {
@@ -1025,20 +989,19 @@ public class VolumeDialog {
+ " onProgressChanged " + progress + " fromUser=" + fromUser);
if (!fromUser) return;
if (mRow.ss.levelMin > 0) {
- final int minProgress = mRow.ss.levelMin * 100;
+ final int minProgress = mRow.ss.levelMin;
if (progress < minProgress) {
seekBar.setProgress(minProgress);
progress = minProgress;
}
}
- final int userLevel = getImpliedLevel(seekBar, progress);
- if (mRow.ss.level != userLevel || mRow.ss.muted && userLevel > 0) {
+ if (mRow.ss.level != progress || mRow.ss.muted && progress > 0) {
mRow.userAttempt = SystemClock.uptimeMillis();
- if (mRow.requestedLevel != userLevel) {
- mController.setStreamVolume(mRow.stream, userLevel);
- mRow.requestedLevel = userLevel;
+ if (mRow.requestedLevel != progress) {
+ mController.setStreamVolume(mRow.stream, progress);
+ mRow.requestedLevel = progress;
Events.writeEvent(mContext, Events.EVENT_TOUCH_LEVEL_CHANGED, mRow.stream,
- userLevel);
+ progress);
}
}
}
@@ -1055,7 +1018,7 @@ public class VolumeDialog {
if (D.BUG) Log.d(TAG, "onStopTrackingTouch"+ " " + mRow.stream);
mRow.tracking = false;
mRow.userAttempt = SystemClock.uptimeMillis();
- int userLevel = getImpliedLevel(seekBar, seekBar.getProgress());
+ final int userLevel = seekBar.getProgress();
Events.writeEvent(mContext, Events.EVENT_TOUCH_LEVEL_DONE, mRow.stream, userLevel);
if (mRow.ss.level != userLevel) {
mHandler.sendMessageDelayed(mHandler.obtainMessage(H.RECHECK, mRow),
@@ -1137,8 +1100,6 @@ public class VolumeDialog {
private int iconState; // from Events
private boolean cachedShowHeaders = VolumePrefs.DEFAULT_SHOW_HEADERS;
private int cachedExpandButtonRes;
- private ObjectAnimator anim; // slider progress animation for non-touch-related updates
- private int animTargetProgress;
private int lastAudibleLevel = 1;
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java
index 32d68054a6af..1cf7a70f7e4d 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java
@@ -284,7 +284,7 @@ public class VolumeDialogController {
return changed;
}
- private void onVolumeChangedW(int stream, int flags) {
+ private boolean onVolumeChangedW(int stream, int flags) {
final boolean showUI = (flags & AudioManager.FLAG_SHOW_UI) != 0;
final boolean fromKey = (flags & AudioManager.FLAG_FROM_KEY) != 0;
final boolean showVibrateHint = (flags & AudioManager.FLAG_SHOW_VIBRATE_HINT) != 0;
@@ -311,6 +311,7 @@ public class VolumeDialogController {
if (changed && fromKey) {
Events.writeEvent(mContext, Events.EVENT_KEY, stream, lastAudibleStreamVolume);
}
+ return changed;
}
private boolean updateActiveStreamW(int activeStream) {
@@ -797,6 +798,7 @@ public class VolumeDialogController {
if (D.BUG) Log.d(TAG, "onReceive STREAM_DEVICES_CHANGED_ACTION stream="
+ stream + " devices=" + devices + " oldDevices=" + oldDevices);
changed = checkRoutedToBluetoothW(stream);
+ changed |= onVolumeChangedW(stream, 0);
} else if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) {
final int rm = intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE, -1);
if (D.BUG) Log.d(TAG, "onReceive RINGER_MODE_CHANGED_ACTION rm="
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java b/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java
index af7ee0856cb6..f156607fb26d 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java
@@ -139,6 +139,7 @@ public class ZenFooter extends LinearLayout {
}
public void onConfigurationChanged() {
+ mEndNowButton.setText(mContext.getString(R.string.volume_zen_end_now));
mSpTexts.update();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarAppsModelTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarAppsModelTest.java
index e7a40d7fc10b..f51e8ff8f02e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarAppsModelTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarAppsModelTest.java
@@ -44,7 +44,6 @@ import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
/** Tests for the data model for the navigation bar app icons. */
@@ -109,8 +108,8 @@ public class NavigationBarAppsModelTest extends AndroidTestCase {
};
}
- /** Tests buildAppLaunchIntent(). */
- public void testBuildAppLaunchIntent() {
+ /** Tests resolveApp(). */
+ public void testResolveApp() {
ActivityInfo mockNonExportedActivityInfo = new ActivityInfo();
mockNonExportedActivityInfo.exported = false;
ActivityInfo mockExportedActivityInfo = new ActivityInfo();
@@ -149,25 +148,27 @@ public class NavigationBarAppsModelTest extends AndroidTestCase {
mModel.setCurrentUser(3);
// Unlauncheable (for various reasons) apps.
- assertEquals(null, mModel.buildAppLaunchIntent(
+ assertEquals(null, mModel.resolveApp(
new AppInfo(new ComponentName("package0", "class0"), new UserHandle(3))));
mModel.setCurrentUser(4);
- assertEquals(null, mModel.buildAppLaunchIntent(
+ assertEquals(null, mModel.resolveApp(
new AppInfo(new ComponentName("package1", "class1"), new UserHandle(4))));
mModel.setCurrentUser(5);
- assertEquals(null, mModel.buildAppLaunchIntent(
+ assertEquals(null, mModel.resolveApp(
new AppInfo(new ComponentName("package2", "class2"), new UserHandle(5))));
mModel.setCurrentUser(6);
- assertEquals(null, mModel.buildAppLaunchIntent(
+ assertEquals(null, mModel.resolveApp(
new AppInfo(new ComponentName("package3", "class3"), new UserHandle(6))));
// A launcheable app.
mModel.setCurrentUser(7);
- Intent intent = mModel.buildAppLaunchIntent(
+ NavigationBarAppsModel.ResolvedApp resolvedApp = mModel.resolveApp(
new AppInfo(new ComponentName("package4", "class4"), new UserHandle(7)));
- assertNotNull(intent);
+ assertNotNull(resolvedApp);
+ Intent intent = resolvedApp.launchIntent;
assertEquals(new ComponentName("package4", "class4"), intent.getComponent());
assertEquals("package4", intent.getPackage());
+ assertEquals(ri1, resolvedApp.ri);
}
/** Initializes the model from SharedPreferences for a few app activites. */
@@ -412,4 +413,19 @@ public class NavigationBarAppsModelTest extends AndroidTestCase {
verify(mMockEdit).apply();
verifyNoMoreInteractions(mMockEdit);
}
+
+ /** Tests the apps-changed listener. */
+ public void testAppsChangedListeners() {
+ NavigationBarAppsModel.OnAppsChangedListener listener =
+ mock(NavigationBarAppsModel.OnAppsChangedListener.class);
+
+ mModel.addOnAppsChangedListener(listener);
+ mModel.setApps(new ArrayList<AppInfo>());
+ verify(listener).onPinnedAppsChanged();
+ verifyNoMoreInteractions(listener);
+
+ mModel.removeOnAppsChangedListener(listener);
+ mModel.setApps(new ArrayList<AppInfo>());
+ verifyNoMoreInteractions(listener);
+ }
}
diff --git a/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp b/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp
index 272733893280..990d7707cdfb 100644
--- a/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp
+++ b/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp
@@ -130,7 +130,7 @@ static jstring com_android_pacprocessor_PacNative_makeProxyRequestNativeLocked(J
return jret;
}
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
{ "createV8ParserNativeLocked", "()Z",
(void*)com_android_pacprocessor_PacNative_createV8ParserNativeLocked},
{ "destroyV8ParserNativeLocked", "()Z",
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index 0419d33c686c..8c830e8d9257 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -2494,7 +2494,7 @@ nSystemGetPointerSize(JNIEnv *_env, jobject _this) {
static const char *classPathName = "android/renderscript/RenderScript";
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
{"_nInit", "()V", (void*)_nInit },
{"nDeviceCreate", "()J", (void*)nDeviceCreate },
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 7051b52cad4e..ff2a2ee3ca26 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -650,6 +650,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
userState.mIsTouchExplorationEnabled = false;
userState.mIsEnhancedWebAccessibilityEnabled = false;
userState.mIsDisplayMagnificationEnabled = false;
+ userState.mIsAutoclickEnabled = false;
userState.mInstalledServices.add(accessibilityServiceInfo);
userState.mEnabledServices.clear();
userState.mEnabledServices.add(sFakeAccessibilityServiceComponentName);
@@ -700,6 +701,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
userState.mIsTouchExplorationEnabled = touchExplorationEnabled;
userState.mIsEnhancedWebAccessibilityEnabled = false;
userState.mIsDisplayMagnificationEnabled = false;
+ userState.mIsAutoclickEnabled = false;
userState.mEnabledServices.clear();
userState.mEnabledServices.add(service);
userState.mBindingServices.clear();
@@ -965,8 +967,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
List<ResolveInfo> installedServices = mPackageManager.queryIntentServicesAsUser(
new Intent(AccessibilityService.SERVICE_INTERFACE),
- PackageManager.GET_SERVICES
- | PackageManager.GET_META_DATA
+ PackageManager.GET_SERVICES
+ | PackageManager.GET_META_DATA
| PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
mCurrentUserId);
@@ -1281,6 +1283,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
if (userState.mIsFilterKeyEventsEnabled) {
flags |= AccessibilityInputFilter.FLAG_FEATURE_FILTER_KEY_EVENTS;
}
+ if (userState.mIsAutoclickEnabled) {
+ flags |= AccessibilityInputFilter.FLAG_FEATURE_AUTOCLICK;
+ }
if (flags != 0) {
if (!mHasInputFilter) {
mHasInputFilter = true;
@@ -1485,6 +1490,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
somthingChanged |= readHighTextContrastEnabledSettingLocked(userState);
somthingChanged |= readEnhancedWebAccessibilityEnabledChangedLocked(userState);
somthingChanged |= readDisplayMagnificationEnabledSettingLocked(userState);
+ somthingChanged |= readAutoclickEnabledSettingLocked(userState);
somthingChanged |= readDisplayColorAdjustmentSettingsLocked(userState);
return somthingChanged;
}
@@ -1523,6 +1529,18 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
return false;
}
+ private boolean readAutoclickEnabledSettingLocked(UserState userState) {
+ final boolean autoclickEnabled = Settings.Secure.getIntForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_AUTOCLICK_ENABLED,
+ 0, userState.mUserId) == 1;
+ if (autoclickEnabled != userState.mIsAutoclickEnabled) {
+ userState.mIsAutoclickEnabled = autoclickEnabled;
+ return true;
+ }
+ return false;
+ }
+
private boolean readEnhancedWebAccessibilityEnabledChangedLocked(UserState userState) {
final boolean enhancedWeAccessibilityEnabled = Settings.Secure.getIntForUser(
mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION,
@@ -1671,6 +1689,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
pw.append(", touchExplorationEnabled=" + userState.mIsTouchExplorationEnabled);
pw.append(", displayMagnificationEnabled="
+ userState.mIsDisplayMagnificationEnabled);
+ pw.append(", autoclickEnabled=" + userState.mIsAutoclickEnabled);
if (userState.mUiAutomationService != null) {
pw.append(", ");
userState.mUiAutomationService.dump(fd, pw, args);
@@ -3198,7 +3217,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
case WindowManager.LayoutParams.TYPE_SYSTEM_ALERT:
case WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG:
case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR:
- case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY: {
+ case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY:
+ case WindowManager.LayoutParams.TYPE_DOCK_DIVIDER: {
return AccessibilityWindowInfo.TYPE_SYSTEM;
}
@@ -3777,6 +3797,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
public boolean mIsTextHighContrastEnabled;
public boolean mIsEnhancedWebAccessibilityEnabled;
public boolean mIsDisplayMagnificationEnabled;
+ public boolean mIsAutoclickEnabled;
public boolean mIsFilterKeyEventsEnabled;
public boolean mHasDisplayColorAdjustment;
public boolean mAccessibilityFocusOnlyInActiveWindow;
@@ -3841,6 +3862,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
mIsTouchExplorationEnabled = false;
mIsEnhancedWebAccessibilityEnabled = false;
mIsDisplayMagnificationEnabled = false;
+ mIsAutoclickEnabled = false;
}
public void destroyUiAutomationService() {
@@ -3865,6 +3887,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
private final Uri mDisplayMagnificationEnabledUri = Settings.Secure.getUriFor(
Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED);
+ private final Uri mAutoclickEnabledUri = Settings.Secure.getUriFor(
+ Settings.Secure.ACCESSIBILITY_AUTOCLICK_ENABLED);
+
private final Uri mEnabledAccessibilityServicesUri = Settings.Secure.getUriFor(
Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
@@ -3897,6 +3922,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
false, this, UserHandle.USER_ALL);
contentResolver.registerContentObserver(mDisplayMagnificationEnabledUri,
false, this, UserHandle.USER_ALL);
+ contentResolver.registerContentObserver(mAutoclickEnabledUri,
+ false, this, UserHandle.USER_ALL);
contentResolver.registerContentObserver(mEnabledAccessibilityServicesUri,
false, this, UserHandle.USER_ALL);
contentResolver.registerContentObserver(
@@ -3938,6 +3965,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
if (readDisplayMagnificationEnabledSettingLocked(userState)) {
onUserStateChangedLocked(userState);
}
+ } else if (mAutoclickEnabledUri.equals(uri)) {
+ if (readAutoclickEnabledSettingLocked(userState)) {
+ onUserStateChangedLocked(userState);
+ }
} else if (mEnabledAccessibilityServicesUri.equals(uri)) {
if (readEnabledAccessibilityServicesLocked(userState)) {
onUserStateChangedLocked(userState);
diff --git a/services/accessibility/java/com/android/server/accessibility/AutoclickController.java b/services/accessibility/java/com/android/server/accessibility/AutoclickController.java
index 318b7b4dbfc1..8989625f979a 100644
--- a/services/accessibility/java/com/android/server/accessibility/AutoclickController.java
+++ b/services/accessibility/java/com/android/server/accessibility/AutoclickController.java
@@ -16,16 +16,28 @@
package com.android.server.accessibility;
+import android.annotation.NonNull;
+import android.content.ContentResolver;
import android.content.Context;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.Slog;
+import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.MotionEvent;
+import android.view.MotionEvent.PointerCoords;
+import android.view.MotionEvent.PointerProperties;
import android.view.accessibility.AccessibilityEvent;
/**
* Implements "Automatically click on mouse stop" feature.
*
- * If enabled, it will observe motion events from mouse source, and send click event sequence short
- * while after mouse stops moving. The click will only be performed if mouse movement had been
+ * If enabled, it will observe motion events from mouse source, and send click event sequence
+ * shortly after mouse stops moving. The click will only be performed if mouse movement had been
* actually detected.
*
* Movement detection has tolerance to jitter that may be caused by poor motor control to prevent:
@@ -36,15 +48,42 @@ import android.view.accessibility.AccessibilityEvent;
*
* Non-mouse motion events, key events (excluding modifiers) and non-movement mouse events cancel
* the automatic click.
+ *
+ * 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.
*/
public class AutoclickController implements EventStreamTransformation {
+
+ public static final int DEFAULT_CLICK_DELAY_MS = 600;
+
+ private static final String LOG_TAG = AutoclickController.class.getSimpleName();
+
private EventStreamTransformation mNext;
+ private final Context mContext;
+
+ // Lazily created on the first mouse motion event.
+ private ClickScheduler mClickScheduler;
+ private ClickDelayObserver mClickDelayObserver;
- public AutoclickController(Context context) {}
+ public AutoclickController(Context context) {
+ mContext = context;
+ }
@Override
public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
- // TODO: Implement this.
+ if (event.isFromSource(InputDevice.SOURCE_MOUSE)) {
+ if (mClickScheduler == null) {
+ Handler handler = new Handler(mContext.getMainLooper());
+ mClickScheduler = new ClickScheduler(handler, DEFAULT_CLICK_DELAY_MS);
+ mClickDelayObserver = new ClickDelayObserver(handler);
+ mClickDelayObserver.start(mContext.getContentResolver(), mClickScheduler);
+ }
+
+ handleMouseMotion(event, policyFlags);
+ } else if (mClickScheduler != null) {
+ mClickScheduler.cancel();
+ }
+
if (mNext != null) {
mNext.onMotionEvent(event, rawEvent, policyFlags);
}
@@ -52,7 +91,14 @@ public class AutoclickController implements EventStreamTransformation {
@Override
public void onKeyEvent(KeyEvent event, int policyFlags) {
- // TODO: Implement this.
+ if (mClickScheduler != null) {
+ if (KeyEvent.isModifierKey(event.getKeyCode())) {
+ mClickScheduler.updateMetaState(event.getMetaState());
+ } else {
+ mClickScheduler.cancel();
+ }
+ }
+
if (mNext != null) {
mNext.onKeyEvent(event, policyFlags);
}
@@ -72,6 +118,10 @@ public class AutoclickController implements EventStreamTransformation {
@Override
public void clearEvents(int inputSource) {
+ if (inputSource == InputDevice.SOURCE_MOUSE && mClickScheduler != null) {
+ mClickScheduler.cancel();
+ }
+
if (mNext != null) {
mNext.clearEvents(inputSource);
}
@@ -79,5 +129,340 @@ public class AutoclickController implements EventStreamTransformation {
@Override
public void onDestroy() {
+ if (mClickDelayObserver != null) {
+ mClickDelayObserver.stop();
+ mClickDelayObserver = null;
+ }
+ if (mClickScheduler != null) {
+ mClickScheduler.cancel();
+ mClickScheduler = null;
+ }
+ }
+
+ private void handleMouseMotion(MotionEvent event, int policyFlags) {
+ switch (event.getActionMasked()) {
+ case MotionEvent.ACTION_HOVER_MOVE: {
+ if (event.getPointerCount() == 1) {
+ mClickScheduler.update(event, policyFlags);
+ } else {
+ mClickScheduler.cancel();
+ }
+ } break;
+ // Ignore hover enter and exit.
+ case MotionEvent.ACTION_HOVER_ENTER:
+ case MotionEvent.ACTION_HOVER_EXIT:
+ break;
+ default:
+ mClickScheduler.cancel();
+ }
+ }
+
+ /**
+ * Observes setting value for autoclick delay, and updates ClickScheduler delay whenever the
+ * setting value changes.
+ */
+ final private static class ClickDelayObserver extends ContentObserver {
+ /** URI used to identify the autoclick delay setting with content resolver. */
+ private final Uri mAutoclickDelaySettingUri = Settings.Secure.getUriFor(
+ Settings.Secure.ACCESSIBILITY_AUTOCLICK_DELAY);
+
+ private ContentResolver mContentResolver;
+ private ClickScheduler mClickScheduler;
+
+ public ClickDelayObserver(Handler handler) {
+ super(handler);
+ }
+
+ /**
+ * Starts the observer. And makes sure up-to-date autoclick delay is propagated to
+ * |clickScheduler|.
+ *
+ * @param contentResolver Content resolver that should be observed for setting's value
+ * changes.
+ * @param clickScheduler ClickScheduler that should be updated when click delay changes.
+ * @throws IllegalStateException If internal state is already setup when the method is
+ * called.
+ * @throws NullPointerException If any of the arguments is a null pointer.
+ */
+ public void start(@NonNull ContentResolver contentResolver,
+ @NonNull ClickScheduler clickScheduler) {
+ if (mContentResolver != null || mClickScheduler != null) {
+ throw new IllegalStateException("Observer already started.");
+ }
+ if (contentResolver == null) {
+ throw new NullPointerException("contentResolver not set.");
+ }
+ if (clickScheduler == null) {
+ throw new NullPointerException("clickScheduler not set.");
+ }
+
+ mContentResolver = contentResolver;
+ mClickScheduler = clickScheduler;
+ mContentResolver.registerContentObserver(mAutoclickDelaySettingUri, false, this,
+ UserHandle.USER_ALL);
+
+ // Initialize mClickScheduler's initial delay value.
+ onChange(true, mAutoclickDelaySettingUri);
+ }
+
+ /**
+ * Stops the the observer. Should only be called if the observer has been started.
+ *
+ * @throws IllegalStateException If internal state hasn't yet been initialized by calling
+ * {@link #start}.
+ */
+ public void stop() {
+ if (mContentResolver == null || mClickScheduler == null) {
+ throw new IllegalStateException("ClickDelayObserver not started.");
+ }
+
+ mContentResolver.unregisterContentObserver(this);
+ }
+
+ @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(
+ mContentResolver, Settings.Secure.ACCESSIBILITY_AUTOCLICK_DELAY,
+ DEFAULT_CLICK_DELAY_MS);
+ mClickScheduler.updateDelay(delay);
+ }
+ }
+ }
+
+ /**
+ * Schedules and performs click event sequence that should be initiated when mouse pointer stops
+ * moving. The click is first scheduled when a mouse movement is detected, and then further
+ * delayed on every sufficient mouse movement.
+ */
+ final private class ClickScheduler implements Runnable {
+ /**
+ * Minimal distance pointer has to move relative to anchor in order for movement not to be
+ * discarded as noise. Anchor is the position of the last MOVE event that was not considered
+ * noise.
+ */
+ private static final double MOVEMENT_SLOPE = 20f;
+
+ /** Whether there is pending click. */
+ private boolean mActive;
+ /** If active, time at which pending click is scheduled. */
+ private long mScheduledClickTime;
+
+ /** Last observed motion event. null if no events have been observed yet. */
+ private MotionEvent mLastMotionEvent;
+ /** Last observed motion event's policy flags. */
+ private int mEventPolicyFlags;
+ /** Current meta state. This value will be used as meta state for click event sequence. */
+ private int mMetaState;
+
+ /**
+ * The current anchor's coordinates. Should be ignored if #mLastMotionEvent is null.
+ * Note that these are not necessary coords of #mLastMotionEvent (because last observed
+ * motion event may have been labeled as noise).
+ */
+ private PointerCoords mAnchorCoords;
+
+ /** Delay that should be used to schedule click. */
+ private int mDelay;
+
+ /** Handler for scheduling delayed operations. */
+ private Handler mHandler;
+
+ private PointerProperties mTempPointerProperties[];
+ private PointerCoords mTempPointerCoords[];
+
+ public ClickScheduler(Handler handler, int delay) {
+ mHandler = handler;
+
+ mLastMotionEvent = null;
+ resetInternalState();
+ mDelay = delay;
+ mAnchorCoords = new PointerCoords();
+ }
+
+ @Override
+ public void run() {
+ long now = SystemClock.uptimeMillis();
+ // Click was rescheduled after task was posted. Post new run task at updated time.
+ if (now < mScheduledClickTime) {
+ mHandler.postDelayed(this, mScheduledClickTime - now);
+ return;
+ }
+
+ sendClick();
+ resetInternalState();
+ }
+
+ /**
+ * Updates properties that should be used for click event sequence initiated by this object,
+ * as well as the time at which click will be scheduled.
+ * Should be called whenever new motion event is observed.
+ *
+ * @param event Motion event whose properties should be used as a base for click event
+ * sequence.
+ * @param policyFlags Policy flags that should be send with click event sequence.
+ */
+ public void update(MotionEvent event, int policyFlags) {
+ mMetaState = event.getMetaState();
+
+ boolean moved = detectMovement(event);
+ cacheLastEvent(event, policyFlags, mLastMotionEvent == null || moved /* useAsAnchor */);
+
+ if (moved) {
+ rescheduleClick(mDelay);
+ }
+ }
+
+ /** Cancels any pending clicks and resets the object state. */
+ public void cancel() {
+ if (!mActive) {
+ return;
+ }
+ resetInternalState();
+ mHandler.removeCallbacks(this);
+ }
+
+ /**
+ * Updates the meta state that should be used for click sequence.
+ */
+ public void updateMetaState(int state) {
+ mMetaState = state;
+ }
+
+ /**
+ * Updates delay that should be used when scheduling clicks. The delay will be used only for
+ * clicks scheduled after this point (pending click tasks are not affected).
+ * @param delay New delay value.
+ */
+ public void updateDelay(int delay) {
+ mDelay = delay;
+ }
+
+ /**
+ * Updates the time at which click sequence should occur.
+ *
+ * @param delay Delay (from now) after which click should occur.
+ */
+ private void rescheduleClick(int delay) {
+ long clickTime = SystemClock.uptimeMillis() + delay;
+ // If there already is a scheduled click at time before the updated time, just update
+ // scheduled time. The click will actually be rescheduled when pending callback is
+ // run.
+ if (mActive && clickTime > mScheduledClickTime) {
+ mScheduledClickTime = clickTime;
+ return;
+ }
+
+ if (mActive) {
+ mHandler.removeCallbacks(this);
+ }
+
+ mActive = true;
+ mScheduledClickTime = clickTime;
+
+ mHandler.postDelayed(this, delay);
+ }
+
+ /**
+ * Updates last observed motion event.
+ *
+ * @param event The last observed event.
+ * @param policyFlags The policy flags used with the last observed event.
+ * @param useAsAnchor Whether the event coords should be used as a new anchor.
+ */
+ private void cacheLastEvent(MotionEvent event, int policyFlags, boolean useAsAnchor) {
+ if (mLastMotionEvent != null) {
+ mLastMotionEvent.recycle();
+ }
+ mLastMotionEvent = MotionEvent.obtain(event);
+ mEventPolicyFlags = policyFlags;
+
+ if (useAsAnchor) {
+ final int pointerIndex = mLastMotionEvent.getActionIndex();
+ mLastMotionEvent.getPointerCoords(pointerIndex, mAnchorCoords);
+ }
+ }
+
+ private void resetInternalState() {
+ mActive = false;
+ if (mLastMotionEvent != null) {
+ mLastMotionEvent.recycle();
+ mLastMotionEvent = null;
+ }
+ mScheduledClickTime = -1;
+ }
+
+ /**
+ * @param event Observed motion event.
+ * @return Whether the event coords are far enough from the anchor for the event not to be
+ * considered noise.
+ */
+ private boolean detectMovement(MotionEvent event) {
+ if (mLastMotionEvent == null) {
+ return false;
+ }
+ final int pointerIndex = event.getActionIndex();
+ float deltaX = mAnchorCoords.x - event.getX(pointerIndex);
+ float deltaY = mAnchorCoords.y - event.getY(pointerIndex);
+ double delta = Math.hypot(deltaX, deltaY);
+ return delta > MOVEMENT_SLOPE;
+ }
+
+ /**
+ * Creates and forwards click event sequence.
+ */
+ private void sendClick() {
+ if (mLastMotionEvent == null || mNext == null) {
+ return;
+ }
+
+ final int pointerIndex = mLastMotionEvent.getActionIndex();
+
+ if (mTempPointerProperties == null) {
+ mTempPointerProperties = new PointerProperties[1];
+ mTempPointerProperties[0] = new PointerProperties();
+ }
+
+ mLastMotionEvent.getPointerProperties(pointerIndex, mTempPointerProperties[0]);
+
+ if (mTempPointerCoords == null) {
+ mTempPointerCoords = new PointerCoords[1];
+ mTempPointerCoords[0] = new PointerCoords();
+ }
+ mLastMotionEvent.getPointerCoords(pointerIndex, mTempPointerCoords[0]);
+
+ final long now = SystemClock.uptimeMillis();
+
+ MotionEvent downEvent = MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN, 1,
+ mTempPointerProperties, mTempPointerCoords, mMetaState,
+ MotionEvent.BUTTON_PRIMARY, 1.0f, 1.0f, mLastMotionEvent.getDeviceId(), 0,
+ mLastMotionEvent.getSource(), mLastMotionEvent.getFlags());
+
+ // The only real difference between these two events is the action flag.
+ MotionEvent upEvent = MotionEvent.obtain(downEvent);
+ upEvent.setAction(MotionEvent.ACTION_UP);
+
+ mNext.onMotionEvent(downEvent, downEvent, mEventPolicyFlags);
+ downEvent.recycle();
+
+ mNext.onMotionEvent(upEvent, upEvent, mEventPolicyFlags);
+ upEvent.recycle();
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("ClickScheduler: { active=").append(mActive);
+ builder.append(", delay=").append(mDelay);
+ builder.append(", scheduledClickTime=").append(mScheduledClickTime);
+ builder.append(", anchor={x:").append(mAnchorCoords.x);
+ builder.append(", y:").append(mAnchorCoords.y).append("}");
+ builder.append(", metastate=").append(mMetaState);
+ builder.append(", policyFlags=").append(mEventPolicyFlags);
+ builder.append(", lastMotionEvent=").append(mLastMotionEvent);
+ builder.append(" }");
+ return builder.toString();
+ }
}
}
diff --git a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
index 85730cdef082..c3f5c43daeb7 100644
--- a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
@@ -29,6 +29,7 @@ import android.graphics.Rect;
import android.os.Handler;
import android.os.SystemClock;
import android.util.Slog;
+import android.view.GestureDetector;
import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -114,9 +115,6 @@ class TouchExplorer implements EventStreamTransformation {
// Timeout within which we try to detect a tap.
private final int mTapTimeout;
- // Timeout within which we try to detect a double tap.
- private final int mDoubleTapTimeout;
-
// Slop between the down and up tap to be a tap.
private final int mTouchSlop;
@@ -230,7 +228,6 @@ class TouchExplorer implements EventStreamTransformation {
mInjectedPointerTracker = new InjectedPointerTracker();
mTapTimeout = ViewConfiguration.getTapTimeout();
mDetermineUserIntentTimeout = ViewConfiguration.getDoubleTapTimeout();
- mDoubleTapTimeout = ViewConfiguration.getDoubleTapTimeout();
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
mDoubleTapSlop = ViewConfiguration.get(context).getScaledDoubleTapSlop();
mHandler = new Handler(context.getMainLooper());
@@ -248,7 +245,7 @@ class TouchExplorer implements EventStreamTransformation {
mSendTouchInteractionEndDelayed = new SendAccessibilityEventDelayed(
AccessibilityEvent.TYPE_TOUCH_INTERACTION_END,
mDetermineUserIntentTimeout);
- mDoubleTapDetector = new DoubleTapDetector();
+ mDoubleTapDetector = new DoubleTapDetector(mContext);
final float density = context.getResources().getDisplayMetrics().density;
mScaledMinPointerDistanceToUseMiddleLocation =
(int) (MIN_POINTER_DISTANCE_TO_USE_MIDDLE_LOCATION_DIP * density);
@@ -1109,66 +1106,63 @@ class TouchExplorer implements EventStreamTransformation {
}
}
- private class DoubleTapDetector {
- private MotionEvent mDownEvent;
- private MotionEvent mFirstTapEvent;
+ private class DoubleTapDetector extends GestureDetector.SimpleOnGestureListener {
+ private final GestureDetector mGestureDetector;
+ private boolean mFirstTapDetected;
+ private boolean mDoubleTapDetected;
+
+ DoubleTapDetector(Context context) {
+ mGestureDetector = new GestureDetector(context, this);
+ mGestureDetector.setOnDoubleTapListener(this);
+ }
public void onMotionEvent(MotionEvent event, int policyFlags) {
- final int actionIndex = event.getActionIndex();
- final int action = event.getActionMasked();
- switch (action) {
+ switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
- case MotionEvent.ACTION_POINTER_DOWN: {
- if (mFirstTapEvent != null
- && !GestureUtils.isSamePointerContext(mFirstTapEvent, event)) {
- clear();
- }
- mDownEvent = MotionEvent.obtain(event);
- } break;
+ mDoubleTapDetected = false;
+ break;
+
case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_POINTER_UP: {
- if (mDownEvent == null) {
- return;
- }
- if (!GestureUtils.isSamePointerContext(mDownEvent, event)) {
- clear();
- return;
- }
- if (GestureUtils.isTap(mDownEvent, event, mTapTimeout, mTouchSlop,
- actionIndex)) {
- if (mFirstTapEvent == null || GestureUtils.isTimedOut(mFirstTapEvent,
- event, mDoubleTapTimeout)) {
- mFirstTapEvent = MotionEvent.obtain(event);
- mDownEvent.recycle();
- mDownEvent = null;
- return;
- }
- if (GestureUtils.isMultiTap(mFirstTapEvent, event, mDoubleTapTimeout,
- mDoubleTapSlop, actionIndex)) {
- onDoubleTap(event, policyFlags);
- mFirstTapEvent.recycle();
- mFirstTapEvent = null;
- mDownEvent.recycle();
- mDownEvent = null;
- return;
- }
- mFirstTapEvent.recycle();
- mFirstTapEvent = null;
- } else {
- if (mFirstTapEvent != null) {
- mFirstTapEvent.recycle();
- mFirstTapEvent = null;
- }
- }
- mDownEvent.recycle();
- mDownEvent = null;
- } break;
+ maybeFinishDoubleTap(event, policyFlags);
+ break;
}
+ mGestureDetector.onTouchEvent(event);
+ }
+
+ @Override
+ public boolean onDown(MotionEvent event) {
+ return true;
+ }
+
+ @Override
+ public boolean onSingleTapUp(MotionEvent event) {
+ mFirstTapDetected = true;
+ return false;
}
- public void onDoubleTap(MotionEvent secondTapUp, int policyFlags) {
+ @Override
+ public boolean onSingleTapConfirmed(MotionEvent event) {
+ clear();
+ return false;
+ }
+
+ @Override
+ public boolean onDoubleTap(MotionEvent event) {
+ // The processing of the double tap is deferred until the finger is
+ // lifted, so that we can detect a long press on the second tap.
+ mDoubleTapDetected = true;
+ return true;
+ }
+
+ private void maybeFinishDoubleTap(MotionEvent event, int policyFlags) {
+ if (!mDoubleTapDetected) {
+ return;
+ }
+
+ clear();
+
// This should never be called when more than two pointers are down.
- if (secondTapUp.getPointerCount() > 2) {
+ if (event.getPointerCount() > 2) {
return;
}
@@ -1184,8 +1178,8 @@ class TouchExplorer implements EventStreamTransformation {
mSendTouchInteractionEndDelayed.forceSendAndRemove();
}
- final int pointerId = secondTapUp.getPointerId(secondTapUp.getActionIndex());
- final int pointerIndex = secondTapUp.findPointerIndex(pointerId);
+ final int pointerId = event.getPointerId(event.getActionIndex());
+ final int pointerIndex = event.findPointerIndex(pointerId);
Point clickLocation = mTempPoint;
final int result = computeClickLocation(clickLocation);
@@ -1196,34 +1190,28 @@ class TouchExplorer implements EventStreamTransformation {
// Do the click.
PointerProperties[] properties = new PointerProperties[1];
properties[0] = new PointerProperties();
- secondTapUp.getPointerProperties(pointerIndex, properties[0]);
+ event.getPointerProperties(pointerIndex, properties[0]);
PointerCoords[] coords = new PointerCoords[1];
coords[0] = new PointerCoords();
coords[0].x = clickLocation.x;
coords[0].y = clickLocation.y;
- MotionEvent event = MotionEvent.obtain(secondTapUp.getDownTime(),
- secondTapUp.getEventTime(), MotionEvent.ACTION_DOWN, 1, properties,
- coords, 0, 0, 1.0f, 1.0f, secondTapUp.getDeviceId(), 0,
- secondTapUp.getSource(), secondTapUp.getFlags());
+ MotionEvent click_event = MotionEvent.obtain(event.getDownTime(),
+ event.getEventTime(), MotionEvent.ACTION_DOWN, 1, properties,
+ coords, 0, 0, 1.0f, 1.0f, event.getDeviceId(), 0,
+ event.getSource(), event.getFlags());
final boolean targetAccessibilityFocus = (result == CLICK_LOCATION_ACCESSIBILITY_FOCUS);
- sendActionDownAndUp(event, policyFlags, targetAccessibilityFocus);
- event.recycle();
+ sendActionDownAndUp(click_event, policyFlags, targetAccessibilityFocus);
+ click_event.recycle();
+ return;
}
public void clear() {
- if (mDownEvent != null) {
- mDownEvent.recycle();
- mDownEvent = null;
- }
- if (mFirstTapEvent != null) {
- mFirstTapEvent.recycle();
- mFirstTapEvent = null;
- }
+ mFirstTapDetected = false;
+ mDoubleTapDetected = false;
}
public boolean firstTapDetected() {
- return mFirstTapEvent != null
- && SystemClock.uptimeMillis() - mFirstTapEvent.getEventTime() < mDoubleTapTimeout;
+ return mFirstTapDetected;
}
}
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index fa87270d6984..02b5b8a90fc2 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -363,7 +363,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
// ... and see if these are hosts we've been awaiting.
// NOTE: We are backing up and restoring only the owner.
- if (newPackageAdded && userId == UserHandle.USER_OWNER) {
+ // TODO: http://b/22388012
+ if (newPackageAdded && userId == UserHandle.USER_SYSTEM) {
final int uid = getUidForPackage(pkgName, userId);
if (uid >= 0 ) {
resolveHostUidLocked(pkgName, uid);
@@ -1870,19 +1871,28 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
return false;
}
- private void deleteProviderLocked(Provider provider) {
- int N = provider.widgets.size();
+ // Remove widgets for provider that are hosted in userId.
+ private void deleteWidgetsLocked(Provider provider, int userId) {
+ final int N = provider.widgets.size();
for (int i = N - 1; i >= 0; i--) {
- Widget widget = provider.widgets.remove(i);
- // Call back with empty RemoteViews
- updateAppWidgetInstanceLocked(widget, null, false);
- // clear out references to this appWidgetId
- widget.host.widgets.remove(widget);
- removeWidgetLocked(widget);
- widget.provider = null;
- pruneHostLocked(widget.host);
- widget.host = null;
+ Widget widget = provider.widgets.get(i);
+ if (userId == UserHandle.USER_ALL
+ || userId == widget.host.getUserId()) {
+ provider.widgets.remove(i);
+ // Call back with empty RemoteViews
+ updateAppWidgetInstanceLocked(widget, null, false);
+ // clear out references to this appWidgetId
+ widget.host.widgets.remove(widget);
+ removeWidgetLocked(widget);
+ widget.provider = null;
+ pruneHostLocked(widget.host);
+ widget.host = null;
+ }
}
+ }
+
+ private void deleteProviderLocked(Provider provider) {
+ deleteWidgetsLocked(provider, UserHandle.USER_ALL);
mProviders.remove(provider);
// no need to send the DISABLE broadcast, since the receiver is gone anyway
@@ -2729,7 +2739,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
Host host = lookupHostLocked(oldHostId);
if (host != null) {
final int uid = getUidForPackage(NEW_KEYGUARD_HOST_PACKAGE,
- UserHandle.USER_OWNER);
+ UserHandle.USER_SYSTEM);
if (uid >= 0) {
host.id = new HostId(uid, KEYGUARD_HOST_ID, NEW_KEYGUARD_HOST_PACKAGE);
}
@@ -2750,7 +2760,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
private static AtomicFile getSavedStateFile(int userId) {
File dir = Environment.getUserSystemDirectory(userId);
File settingsFile = getStateFile(userId);
- if (!settingsFile.exists() && userId == UserHandle.USER_OWNER) {
+ if (!settingsFile.exists() && userId == UserHandle.USER_SYSTEM) {
if (!dir.exists()) {
dir.mkdirs();
}
@@ -2930,6 +2940,19 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
return providersUpdated;
}
+ // Remove widgets for provider in userId that are hosted in parentUserId
+ private void removeWidgetsForPackageLocked(String pkgName, int userId, int parentUserId) {
+ final int N = mProviders.size();
+ for (int i = 0; i < N; ++i) {
+ Provider provider = mProviders.get(i);
+ if (pkgName.equals(provider.info.provider.getPackageName())
+ && provider.getUserId() == userId
+ && provider.widgets.size() > 0) {
+ deleteWidgetsLocked(provider, parentUserId);
+ }
+ }
+ }
+
private boolean removeProvidersForPackageLocked(String pkgName, int userId) {
boolean removed = false;
@@ -3041,14 +3064,14 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
userId, null);
}
- // Some packages are no longer whitelisted.
+ // Remove widgets from hosts in parent user for packages not in the whitelist
final int removedCount = previousPackages.size();
for (int i = 0; i < removedCount; ++i) {
- providersChanged |= removeProvidersForPackageLocked(
- previousPackages.valueAt(i), userId);
+ removeWidgetsForPackageLocked(previousPackages.valueAt(i),
+ userId, parentId);
}
- if (providersChanged) {
+ if (providersChanged || removedCount > 0) {
saveGroupStateAsync(userId);
scheduleNotifyGroupHostsForProvidersChangedLocked(userId);
}
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index ff02b9453463..2264c69b429c 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -338,7 +338,7 @@ public class BackupManagerService {
@Override
public void onBootPhase(int phase) {
if (phase == PHASE_SYSTEM_SERVICES_READY) {
- sInstance.initialize(UserHandle.USER_OWNER);
+ sInstance.initialize(UserHandle.USER_SYSTEM);
} else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
ContentResolver r = sInstance.mContext.getContentResolver();
boolean areEnabled = Settings.Secure.getInt(r,
@@ -934,7 +934,7 @@ public class BackupManagerService {
case MSG_WIDGET_BROADCAST:
{
final Intent intent = (Intent) msg.obj;
- mContext.sendBroadcastAsUser(intent, UserHandle.OWNER);
+ mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM);
break;
}
}
@@ -1092,8 +1092,9 @@ public class BackupManagerService {
if (DEBUG) Slog.v(TAG, "Starting with transport " + mCurrentTransport);
// Find all transport hosts and bind to their services
+ // TODO: http://b/22388012
List<ResolveInfo> hosts = mPackageManager.queryIntentServicesAsUser(
- mTransportServiceIntent, 0, UserHandle.USER_OWNER);
+ mTransportServiceIntent, 0, UserHandle.USER_SYSTEM);
if (DEBUG) {
Slog.v(TAG, "Found transports: " + ((hosts == null) ? "null" : hosts.size()));
}
@@ -1953,8 +1954,9 @@ public class BackupManagerService {
void checkForTransportAndBind(PackageInfo pkgInfo) {
Intent intent = new Intent(mTransportServiceIntent)
.setPackage(pkgInfo.packageName);
+ // TODO: http://b/22388012
List<ResolveInfo> hosts = mPackageManager.queryIntentServicesAsUser(
- intent, 0, UserHandle.USER_OWNER);
+ intent, 0, UserHandle.USER_SYSTEM);
if (hosts != null) {
final int N = hosts.size();
for (int i = 0; i < N; i++) {
@@ -2002,9 +2004,10 @@ public class BackupManagerService {
mContext.unbindService(connection);
}
}
+ // TODO: http://b/22388012
return mContext.bindServiceAsUser(intent,
connection, Context.BIND_AUTO_CREATE,
- UserHandle.OWNER);
+ UserHandle.SYSTEM);
}
// Add the backup agents in the given packages to our set of known backup participants.
@@ -2853,8 +2856,9 @@ public class BackupManagerService {
private void writeWidgetPayloadIfAppropriate(FileDescriptor fd, String pkgName)
throws IOException {
+ // TODO: http://b/22388012
byte[] widgetState = AppWidgetBackupBridge.getWidgetState(pkgName,
- UserHandle.USER_OWNER);
+ UserHandle.USER_SYSTEM);
// has the widget state changed since last time?
final File widgetFile = new File(mStateDir, pkgName + "_widget");
final boolean priorStateExists = widgetFile.exists();
@@ -3398,8 +3402,9 @@ public class BackupManagerService {
&& ((app.flags & ApplicationInfo.FLAG_SYSTEM) == 0 ||
(app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0);
+ // TODO: http://b/22388012
byte[] widgetBlob = AppWidgetBackupBridge.getWidgetState(pkg.packageName,
- UserHandle.USER_OWNER);
+ UserHandle.USER_SYSTEM);
final int token = generateToken();
FullBackupRunner runner = new FullBackupRunner(pkg, agent, pipes[1],
@@ -3463,7 +3468,8 @@ public class BackupManagerService {
// Save associated .obb content if it exists and we did save the apk
// check for .obb and save those too
- final UserEnvironment userEnv = new UserEnvironment(UserHandle.USER_OWNER);
+ // TODO: http://b/22388012
+ final UserEnvironment userEnv = new UserEnvironment(UserHandle.USER_SYSTEM);
final File obbDir = userEnv.buildExternalStorageAppObbDirs(pkg.packageName)[0];
if (obbDir != null) {
if (MORE_DEBUG) Log.i(TAG, "obb dir: " + obbDir.getAbsolutePath());
@@ -3803,8 +3809,9 @@ public class BackupManagerService {
// If we're doing widget state as well, ensure that we have all the involved
// host & provider packages in the set
if (mDoWidgets) {
+ // TODO: http://b/22388012
List<String> pkgs =
- AppWidgetBackupBridge.getWidgetParticipants(UserHandle.USER_OWNER);
+ AppWidgetBackupBridge.getWidgetParticipants(UserHandle.USER_SYSTEM);
if (pkgs != null) {
if (MORE_DEBUG) {
Slog.i(TAG, "Adding widget participants to backup set:");
@@ -7232,7 +7239,8 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
// Used by both incremental and full restore
void restoreWidgetData(String packageName, byte[] widgetData) {
// Apply the restored widget state and generate the ID update for the app
- AppWidgetBackupBridge.restoreWidgetState(packageName, widgetData, UserHandle.USER_OWNER);
+ // TODO: http://b/22388012
+ AppWidgetBackupBridge.restoreWidgetState(packageName, widgetData, UserHandle.USER_SYSTEM);
}
// *****************************
@@ -7489,7 +7497,8 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
// If we're starting a full-system restore, set up to begin widget ID remapping
if (mIsSystemRestore) {
- AppWidgetBackupBridge.restoreStarting(UserHandle.USER_OWNER);
+ // TODO: http://b/22388012
+ AppWidgetBackupBridge.restoreStarting(UserHandle.USER_SYSTEM);
}
try {
@@ -8095,7 +8104,8 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
}
// Kick off any work that may be needed regarding app widget restores
- AppWidgetBackupBridge.restoreFinished(UserHandle.USER_OWNER);
+ // TODO: http://b/22388012
+ AppWidgetBackupBridge.restoreFinished(UserHandle.USER_SYSTEM);
// If this was a full-system restore, record the ancestral
// dataset information
@@ -8482,7 +8492,8 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
public void dataChanged(final String packageName) {
final int callingUserHandle = UserHandle.getCallingUserId();
- if (callingUserHandle != UserHandle.USER_OWNER) {
+ if (callingUserHandle != UserHandle.USER_SYSTEM) {
+ // TODO: http://b/22388012
// App is running under a non-owner user profile. For now, we do not back
// up data from secondary user profiles.
// TODO: backups for all user profiles although don't add backup for profiles
@@ -8605,7 +8616,8 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "fullBackup");
final int callingUserHandle = UserHandle.getCallingUserId();
- if (callingUserHandle != UserHandle.USER_OWNER) {
+ // TODO: http://b/22388012
+ if (callingUserHandle != UserHandle.USER_SYSTEM) {
throw new IllegalStateException("Backup supported only for the device owner");
}
@@ -8677,7 +8689,8 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
"fullTransportBackup");
final int callingUserHandle = UserHandle.getCallingUserId();
- if (callingUserHandle != UserHandle.USER_OWNER) {
+ // TODO: http://b/22388012
+ if (callingUserHandle != UserHandle.USER_SYSTEM) {
throw new IllegalStateException("Restore supported only for the device owner");
}
@@ -8717,7 +8730,8 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "fullRestore");
final int callingUserHandle = UserHandle.getCallingUserId();
- if (callingUserHandle != UserHandle.USER_OWNER) {
+ // TODO: http://b/22388012
+ if (callingUserHandle != UserHandle.USER_SYSTEM) {
throw new IllegalStateException("Restore supported only for the device owner");
}
diff --git a/services/backup/java/com/android/server/backup/Trampoline.java b/services/backup/java/com/android/server/backup/Trampoline.java
index 5859c6a223d0..a51ab55e2a74 100644
--- a/services/backup/java/com/android/server/backup/Trampoline.java
+++ b/services/backup/java/com/android/server/backup/Trampoline.java
@@ -62,7 +62,8 @@ public class Trampoline extends IBackupManager.Stub {
// internal control API
public void initialize(final int whichUser) {
// Note that only the owner user is currently involved in backup/restore
- if (whichUser == UserHandle.USER_OWNER) {
+ // TODO: http://b/22388012
+ if (whichUser == UserHandle.USER_SYSTEM) {
// Does this product support backup/restore at all?
if (mGlobalDisable) {
Slog.i(TAG, "Backup/restore not supported");
@@ -91,8 +92,8 @@ public class Trampoline extends IBackupManager.Stub {
Slog.i(TAG, "Backup/restore not supported");
return;
}
-
- if (userHandle == UserHandle.USER_OWNER) {
+ // TODO: http://b/22388012
+ if (userHandle == UserHandle.USER_SYSTEM) {
synchronized (this) {
if (makeActive != isBackupServiceActive(userHandle)) {
Slog.i(TAG, "Making backup "
@@ -120,7 +121,8 @@ public class Trampoline extends IBackupManager.Stub {
* @return true if the service is active.
*/
public boolean isBackupServiceActive(final int userHandle) {
- if (userHandle == UserHandle.USER_OWNER) {
+ // TODO: http://b/22388012
+ if (userHandle == UserHandle.USER_SYSTEM) {
synchronized (this) {
return mService != null;
}
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index d5c4a41f07b2..fd67b4148b89 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -271,7 +271,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
int sysUiUid = -1;
try {
sysUiUid = mContext.getPackageManager().getPackageUid("com.android.systemui",
- UserHandle.USER_OWNER);
+ UserHandle.USER_SYSTEM);
} catch (PackageManager.NameNotFoundException e) {
// Some platforms, such as wearables do not have a system ui.
Log.w(TAG, "Unable to resolve SystemUI's UID.", e);
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index d1e1683d6478..6190a5ab357e 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -2270,8 +2270,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
mNetworkRequestInfoLogs.log("REGISTER " + nri);
if (!nri.isRequest) {
for (NetworkAgentInfo network : mNetworkAgentInfos.values()) {
- if (network.satisfiesImmutableCapabilitiesOf(nri.request)) {
- updateSignalStrengthThresholds(network);
+ if (nri.request.networkCapabilities.hasSignalStrength() &&
+ network.satisfiesImmutableCapabilitiesOf(nri.request)) {
+ updateSignalStrengthThresholds(network, "REGISTER", nri.request);
}
}
}
@@ -2388,8 +2389,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
// if this listen request applies and remove it.
for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
nai.networkRequests.remove(nri.request.requestId);
- if (nai.satisfiesImmutableCapabilitiesOf(nri.request)) {
- updateSignalStrengthThresholds(nai);
+ if (nri.request.networkCapabilities.hasSignalStrength() &&
+ nai.satisfiesImmutableCapabilitiesOf(nri.request)) {
+ updateSignalStrengthThresholds(nai, "RELEASE", nri.request);
}
}
}
@@ -3639,9 +3641,24 @@ public class ConnectivityService extends IConnectivityManager.Stub
return new ArrayList<Integer>(thresholds);
}
- private void updateSignalStrengthThresholds(NetworkAgentInfo nai) {
+ private void updateSignalStrengthThresholds(
+ NetworkAgentInfo nai, String reason, NetworkRequest request) {
+ ArrayList<Integer> thresholdsArray = getSignalStrengthThresholds(nai);
Bundle thresholds = new Bundle();
- thresholds.putIntegerArrayList("thresholds", getSignalStrengthThresholds(nai));
+ thresholds.putIntegerArrayList("thresholds", thresholdsArray);
+
+ // TODO: Switch to VDBG.
+ if (DBG) {
+ String detail;
+ if (request != null && request.networkCapabilities.hasSignalStrength()) {
+ detail = reason + " " + request.networkCapabilities.getSignalStrength();
+ } else {
+ detail = reason;
+ }
+ log(String.format("updateSignalStrengthThresholds: %s, sending %s to %s",
+ detail, Arrays.toString(thresholdsArray.toArray()), nai.name()));
+ }
+
nai.asyncChannel.sendMessage(
android.net.NetworkAgent.CMD_SET_SIGNAL_STRENGTH_THRESHOLDS,
0, 0, thresholds);
@@ -4624,7 +4641,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
// so we could decide to tear it down immediately afterwards. That's fine though - on
// disconnection NetworkAgents should stop any signal strength monitoring they have been
// doing.
- updateSignalStrengthThresholds(networkAgent);
+ updateSignalStrengthThresholds(networkAgent, "CONNECT", null);
// Consider network even though it is not yet validated.
rematchNetworkAndRequests(networkAgent, ReapUnvalidatedNetworks.REAP);
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index 46fd28a62108..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
@@ -1523,13 +1566,13 @@ public class DeviceIdleController extends SystemService
private void reportPowerSaveWhitelistChangedLocked() {
Intent intent = new Intent(PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
- getContext().sendBroadcastAsUser(intent, UserHandle.OWNER);
+ getContext().sendBroadcastAsUser(intent, UserHandle.SYSTEM);
}
private void reportTempWhitelistChangedLocked() {
Intent intent = new Intent(PowerManager.ACTION_POWER_SAVE_TEMP_WHITELIST_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
- getContext().sendBroadcastAsUser(intent, UserHandle.OWNER);
+ getContext().sendBroadcastAsUser(intent, UserHandle.SYSTEM);
}
void readConfigFileLocked() {
@@ -1689,7 +1732,7 @@ public class DeviceIdleController extends SystemService
}
if (args != null) {
- int userId = UserHandle.USER_OWNER;
+ int userId = UserHandle.USER_SYSTEM;
for (int i=0; i<args.length; i++) {
String arg = args[i];
if ("-h".equals(arg)) {
@@ -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/DropBoxManagerService.java b/services/core/java/com/android/server/DropBoxManagerService.java
index b9db89ecae64..245448748766 100644
--- a/services/core/java/com/android/server/DropBoxManagerService.java
+++ b/services/core/java/com/android/server/DropBoxManagerService.java
@@ -170,7 +170,7 @@ public final class DropBoxManagerService extends SystemService {
@Override
public void handleMessage(Message msg) {
if (msg.what == MSG_SEND_BROADCAST) {
- getContext().sendBroadcastAsUser((Intent)msg.obj, UserHandle.OWNER,
+ getContext().sendBroadcastAsUser((Intent)msg.obj, UserHandle.SYSTEM,
android.Manifest.permission.READ_LOGS);
}
}
@@ -488,7 +488,7 @@ public final class DropBoxManagerService extends SystemService {
///////////////////////////////////////////////////////////////////////////
- /** Chronologically sorted list of {@link #EntryFile} */
+ /** Chronologically sorted list of {@link EntryFile} */
private static final class FileList implements Comparable<FileList> {
public int blocks = 0;
public final TreeSet<EntryFile> contents = new TreeSet<EntryFile>();
@@ -613,7 +613,7 @@ public final class DropBoxManagerService extends SystemService {
/**
* Creates a EntryFile object with only a timestamp for comparison purposes.
- * @param timestampMillis to compare with.
+ * @param millis to compare with.
*/
public EntryFile(long millis) {
this.tag = null;
diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags
index b826cfda0952..9bf2aaad597e 100644
--- a/services/core/java/com/android/server/EventLogTags.logtags
+++ b/services/core/java/com/android/server/EventLogTags.logtags
@@ -29,6 +29,9 @@ option java_package com.android.server
# This is logged when the partial wake lock (keeping the device awake
# regardless of whether the screen is off) is acquired or released.
2729 power_partial_wake_state (releasedorAcquired|1|5),(tag|3)
+# The device is being asked to go into a soft sleep (typically by the ungaze gesture).
+# It logs the time remaining before the device would've normally gone to sleep without the request.
+2731 power_soft_sleep_requested (savedwaketimems|2)
#
# Leave IDs through 2739 for more power logs (2730 used by battery_discharge above)
diff --git a/services/core/java/com/android/server/GestureLauncherService.java b/services/core/java/com/android/server/GestureLauncherService.java
index 69f0cef6d39e..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;
@@ -101,8 +102,7 @@ public class GestureLauncherService extends SystemService {
* Whether camera double tap power button gesture is currently enabled;
*/
private boolean mCameraDoubleTapPowerEnabled;
- private long mLastPowerDownWhileNonInteractive = 0;
-
+ private long mLastPowerDown;
public GestureLauncherService(Context context) {
super(context);
@@ -251,29 +251,34 @@ public class GestureLauncherService extends SystemService {
public boolean interceptPowerKeyDown(KeyEvent event, boolean interactive) {
boolean launched = false;
+ boolean intercept = false;
+ long doubleTapInterval;
synchronized (this) {
- if (!mCameraDoubleTapPowerEnabled) {
- mLastPowerDownWhileNonInteractive = 0;
- return false;
- }
- if (event.getEventTime() - mLastPowerDownWhileNonInteractive
- < CAMERA_POWER_DOUBLE_TAP_TIME_MS) {
+ doubleTapInterval = event.getEventTime() - mLastPowerDown;
+ if (mCameraDoubleTapPowerEnabled
+ && doubleTapInterval < CAMERA_POWER_DOUBLE_TAP_TIME_MS) {
launched = true;
+ intercept = interactive;
}
- mLastPowerDownWhileNonInteractive = interactive ? 0 : event.getEventTime();
+ mLastPowerDown = event.getEventTime();
}
if (launched) {
Slog.i(TAG, "Power button double tap gesture detected, launching camera.");
launched = handleCameraLaunchGesture(false /* useWakelock */,
- MetricsLogger.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE);
+ StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP);
+ if (launched) {
+ MetricsLogger.action(mContext, MetricsLogger.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE,
+ (int) doubleTapInterval);
+ }
}
- return launched;
+ MetricsLogger.histogram(mContext, "power_double_tap_interval", (int) doubleTapInterval);
+ return intercept && launched;
}
/**
* @return true if camera was launched, false otherwise.
*/
- private boolean handleCameraLaunchGesture(boolean useWakelock, int logCategory) {
+ private boolean handleCameraLaunchGesture(boolean useWakelock, int source) {
boolean userSetupComplete = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.USER_SETUP_COMPLETE, 0) != 0;
if (!userSetupComplete) {
@@ -292,8 +297,7 @@ public class GestureLauncherService extends SystemService {
}
StatusBarManagerInternal service = LocalServices.getService(
StatusBarManagerInternal.class);
- service.onCameraLaunchGestureDetected();
- MetricsLogger.action(mContext, logCategory);
+ service.onCameraLaunchGestureDetected(source);
return true;
}
@@ -333,7 +337,8 @@ public class GestureLauncherService extends SystemService {
"values=[%.4f, %.4f, %.4f].", values[0], values[1], values[2]));
}
if (handleCameraLaunchGesture(true /* useWakelock */,
- MetricsLogger.ACTION_WIGGLE_CAMERA_GESTURE)) {
+ StatusBarManager.CAMERA_LAUNCH_SOURCE_WIGGLE)) {
+ MetricsLogger.action(mContext, MetricsLogger.ACTION_WIGGLE_CAMERA_GESTURE);
trackCameraLaunchEvent(event);
}
return;
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index b418abaae4d4..9dad7a181a06 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -541,7 +541,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
prevSubtypes.addAll(entry.getValue());
}
- final String mergedImesAndSubtypesString = buildInputMethodsAndSubtypesString(prevMap);
+ final String mergedImesAndSubtypesString =
+ InputMethodUtils.buildInputMethodsAndSubtypesString(prevMap);
if (DEBUG_RESTORE) {
Slog.i(TAG, "Merged IME string:");
Slog.i(TAG, " " + mergedImesAndSubtypesString);
@@ -550,23 +551,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
Settings.Secure.ENABLED_INPUT_METHODS, mergedImesAndSubtypesString);
}
- // TODO: Move this method to InputMethodUtils with adding unit tests.
- static String buildInputMethodsAndSubtypesString(ArrayMap<String, ArraySet<String>> map) {
- // we want to use the canonical InputMethodSettings implementation,
- // so we convert data structures first.
- List<Pair<String, ArrayList<String>>> imeMap = new ArrayList<>(4);
- for (ArrayMap.Entry<String, ArraySet<String>> entry : map.entrySet()) {
- final String imeName = entry.getKey();
- final ArraySet<String> subtypeSet = entry.getValue();
- final ArrayList<String> subtypes = new ArrayList<>(2);
- if (subtypeSet != null) {
- subtypes.addAll(subtypeSet);
- }
- imeMap.add(new Pair<>(imeName, subtypes));
- }
- return InputMethodSettings.buildInputMethodsSettingString(imeMap);
- }
-
class MyPackageMonitor extends PackageMonitor {
private boolean isChangingPackagesOfCurrentUser() {
final int userId = getChangingUserId();
@@ -3504,7 +3488,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
throw new NullPointerException("methodMap is null");
}
mMethodMap = methodMap;
- final File systemDir = userId == UserHandle.USER_OWNER
+ final File systemDir = userId == UserHandle.USER_SYSTEM
? new File(Environment.getDataDirectory(), SYSTEM_PATH)
: Environment.getUserSystemDirectory(userId);
final File inputMethodDir = new File(systemDir, INPUT_METHOD_PATH);
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 885c765f3f4b..087ddd6fd882 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -211,8 +211,8 @@ public class LocationManagerService extends ILocationManager.Stub {
new ArrayList<LocationProviderProxy>();
// current active user on the device - other users are denied location data
- private int mCurrentUserId = UserHandle.USER_OWNER;
- private int[] mCurrentUserProfiles = new int[] { UserHandle.USER_OWNER };
+ private int mCurrentUserId = UserHandle.USER_SYSTEM;
+ private int[] mCurrentUserProfiles = new int[] { UserHandle.USER_SYSTEM };
public LocationManagerService(Context context) {
super();
@@ -1832,7 +1832,8 @@ public class LocationManagerService extends ILocationManager.Stub {
// geo-fence manager uses the public location API, need to clear identity
int uid = Binder.getCallingUid();
- if (UserHandle.getUserId(uid) != UserHandle.USER_OWNER) {
+ // TODO: http://b/23822629
+ if (UserHandle.getUserId(uid) != UserHandle.USER_SYSTEM) {
// temporary measure until geofences work for secondary users
Log.w(TAG, "proximity alerts are currently available only to the primary user");
return;
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index c7e0c98ba9cf..da8152861edf 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -145,7 +145,8 @@ public class LockSettingsService extends ILockSettings.Stub {
} catch (RemoteException e) {
Slog.e(TAG, "Failure retrieving IGateKeeperService", e);
}
- mStorage.prefetchUser(UserHandle.USER_OWNER);
+ // TODO: maybe skip this for split system user mode.
+ mStorage.prefetchUser(UserHandle.USER_SYSTEM);
}
private void migrateOldData() {
diff --git a/services/core/java/com/android/server/LockSettingsStrongAuth.java b/services/core/java/com/android/server/LockSettingsStrongAuth.java
index c023f4aa17a0..0e4d5a7f2a7b 100644
--- a/services/core/java/com/android/server/LockSettingsStrongAuth.java
+++ b/services/core/java/com/android/server/LockSettingsStrongAuth.java
@@ -132,7 +132,7 @@ public class LockSettingsStrongAuth {
}
public void requireStrongAuth(int strongAuthReason, int userId) {
- if (userId == UserHandle.USER_ALL || userId >= UserHandle.USER_OWNER) {
+ if (userId == UserHandle.USER_ALL || userId >= UserHandle.USER_SYSTEM) {
mHandler.obtainMessage(MSG_REQUIRE_STRONG_AUTH, strongAuthReason,
userId).sendToTarget();
} else {
diff --git a/services/core/java/com/android/server/MmsServiceBroker.java b/services/core/java/com/android/server/MmsServiceBroker.java
index e0352e091af7..33f92344f615 100644
--- a/services/core/java/com/android/server/MmsServiceBroker.java
+++ b/services/core/java/com/android/server/MmsServiceBroker.java
@@ -500,7 +500,7 @@ public class MmsServiceBroker extends SystemService {
private Uri adjustUriForUserAndGrantPermission(Uri contentUri, String action,
int permission) {
final int callingUserId = UserHandle.getCallingUserId();
- if (callingUserId != UserHandle.USER_OWNER) {
+ if (callingUserId != UserHandle.USER_SYSTEM) {
contentUri = ContentProvider.maybeAddUserId(contentUri, callingUserId);
}
long token = Binder.clearCallingIdentity();
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index 540f8cb8557c..c3d32c2a870b 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -2981,7 +2981,7 @@ class MountService extends IMountService.Stub
Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
if (mContext.bindServiceAsUser(service, mDefContainerConn, Context.BIND_AUTO_CREATE,
- UserHandle.OWNER)) {
+ UserHandle.SYSTEM)) {
mBound = true;
return true;
}
@@ -3014,7 +3014,6 @@ class MountService extends IMountService.Stub
Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
handleError();
- return;
} else {
handleExecute();
if (DEBUG_OBB)
@@ -3176,8 +3175,6 @@ class MountService extends IMountService.Stub
waitForReady();
warnOnNotMounted();
- final ObbInfo obbInfo = getObbInfo();
-
final ObbState existingState;
synchronized (mObbMounts) {
existingState = mObbPathToStateMap.get(mObbState.rawPath);
diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
index b05a6908aee5..b984e1938758 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -133,8 +133,8 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
filter.addDataSchemeSpecificPart(scorer.mPackageName,
PatternMatcher.PATTERN_LITERAL);
mReceiver = new ScorerChangedReceiver(scorer.mPackageName);
- // TODO: Need to update when we support per-user scorers.
- mContext.registerReceiverAsUser(mReceiver, UserHandle.OWNER, filter, null, null);
+ // TODO: Need to update when we support per-user scorers. http://b/23422763
+ mContext.registerReceiverAsUser(mReceiver, UserHandle.SYSTEM, filter, null, null);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Registered receiver for " + scorer.mPackageName);
}
diff --git a/services/core/java/com/android/server/TextServicesManagerService.java b/services/core/java/com/android/server/TextServicesManagerService.java
index aace66c7745d..fc3a322670ee 100644
--- a/services/core/java/com/android/server/TextServicesManagerService.java
+++ b/services/core/java/com/android/server/TextServicesManagerService.java
@@ -99,7 +99,7 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
broadcastFilter.addAction(Intent.ACTION_USER_REMOVED);
mContext.registerReceiver(new TextServicesBroadcastReceiver(), broadcastFilter);
- int userId = UserHandle.USER_OWNER;
+ int userId = UserHandle.USER_SYSTEM;
try {
ActivityManagerNative.getDefault().registerUserSwitchObserver(
new IUserSwitchObserver.Stub() {
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/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 30f4dce310ca..c2284224502d 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -59,6 +59,7 @@ public class VibratorService extends IVibratorService.Stub
implements InputManager.InputDeviceListener {
private static final String TAG = "VibratorService";
private static final boolean DEBUG = false;
+ private static final String SYSTEM_UI_PACKAGE = "com.android.systemui";
private final LinkedList<Vibration> mVibrations;
private final LinkedList<VibrationInfo> mPreviousVibrations;
@@ -147,7 +148,8 @@ public class VibratorService extends IVibratorService.Stub
}
public boolean isSystemHapticFeedback() {
- return (mUid == Process.SYSTEM_UID || mUid == 0) && mRepeat < 0;
+ return (mUid == Process.SYSTEM_UID || mUid == 0 || SYSTEM_UI_PACKAGE.equals(mOpPkg))
+ && mRepeat < 0;
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 14376d1bdb80..bd10c63edbda 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -19,7 +19,6 @@ package com.android.server.am;
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.FREEFORM_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.DOCKED_STACK_ID;
import static android.app.ActivityManager.HOME_STACK_ID;
import static android.app.ActivityManager.INVALID_STACK_ID;
@@ -34,6 +33,7 @@ import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST;
import static com.android.server.am.ActivityManagerDebugConfig.*;
import static com.android.server.am.ActivityStackSupervisor.FORCE_FOCUS;
import static com.android.server.am.ActivityStackSupervisor.ON_TOP;
+import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
@@ -215,7 +215,6 @@ import android.os.ServiceManager;
import android.os.StrictMode;
import android.os.SystemClock;
import android.os.SystemProperties;
-import android.os.Trace;
import android.os.UpdateLock;
import android.os.UserHandle;
import android.os.UserManager;
@@ -323,6 +322,9 @@ public final class ActivityManagerService extends ActivityManagerNative
// How long we wait for a launched process to attach to the activity manager
// before we decide it's never going to come up for real.
static final int PROC_START_TIMEOUT = 10*1000;
+ // How long we wait for an attached process to publish its content providers
+ // before we decide it must be hung.
+ static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT = 10*1000;
// How long we wait for a launched process to attach to the activity manager
// before we decide it's never going to come up for real, when the process was
@@ -992,6 +994,8 @@ public final class ActivityManagerService extends ActivityManagerNative
*/
int mConfigurationSeq = 0;
+ boolean mSuppressResizeConfigChanges = false;
+
/**
* Hardware-reported OpenGLES version.
*/
@@ -1380,6 +1384,7 @@ public final class ActivityManagerService extends ActivityManagerNative
static final int REPORT_USER_SWITCH_COMPLETE_MSG = 56;
static final int SHUTDOWN_UI_AUTOMATION_CONNECTION_MSG = 57;
static final int APP_BOOST_DEACTIVATE_MSG = 58;
+ static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG = 59;
static final int FIRST_ACTIVITY_STACK_MSG = 100;
static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -1716,6 +1721,12 @@ public final class ActivityManagerService extends ActivityManagerNative
processStartTimedOutLocked(app);
}
} break;
+ case CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG: {
+ ProcessRecord app = (ProcessRecord)msg.obj;
+ synchronized (ActivityManagerService.this) {
+ processContentProviderPublishTimedOutLocked(app);
+ }
+ } break;
case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
synchronized (ActivityManagerService.this) {
mStackSupervisor.doPendingActivityLaunchesLocked(true);
@@ -2012,7 +2023,7 @@ public final class ActivityManagerService extends ActivityManagerNative
intent, PendingIntent.FLAG_CANCEL_CURRENT, null,
new UserHandle(userId)))
.setDeleteIntent(PendingIntent.getBroadcastAsUser(mContext, 0,
- deleteIntent, 0, UserHandle.OWNER))
+ deleteIntent, 0, UserHandle.SYSTEM))
.build();
try {
@@ -2370,8 +2381,8 @@ public final class ActivityManagerService extends ActivityManagerNative
mGrantFile = new AtomicFile(new File(systemDir, "urigrants.xml"));
// User 0 is the first and only user that runs at boot.
- mStartedUsers.put(UserHandle.USER_OWNER, new UserState(UserHandle.OWNER, true));
- mUserLru.add(UserHandle.USER_OWNER);
+ mStartedUsers.put(UserHandle.USER_SYSTEM, new UserState(UserHandle.SYSTEM, true));
+ mUserLru.add(UserHandle.USER_SYSTEM);
updateStartedUserArrayLocked();
GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
@@ -4618,7 +4629,7 @@ public final class ActivityManagerService extends ActivityManagerNative
// is hosted by the process... then make sure all visible
// activities are running, taking care of restarting this
// process.
- mStackSupervisor.ensureActivitiesVisibleLocked(null, 0);
+ mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
}
}
@@ -5638,7 +5649,7 @@ public final class ActivityManagerService extends ActivityManagerNative
try {
// Entire package setting changed
enabled = pm.getApplicationEnabledSetting(packageName,
- (userId != UserHandle.USER_ALL) ? userId : UserHandle.USER_OWNER);
+ (userId != UserHandle.USER_ALL) ? userId : UserHandle.USER_SYSTEM);
} catch (Exception e) {
// No such package/component; probably racing with uninstall. In any
// event it means we have nothing further to do here.
@@ -5656,7 +5667,7 @@ public final class ActivityManagerService extends ActivityManagerNative
try {
enabled = pm.getComponentEnabledSetting(
new ComponentName(packageName, changedClass),
- (userId != UserHandle.USER_ALL) ? userId : UserHandle.USER_OWNER);
+ (userId != UserHandle.USER_ALL) ? userId : UserHandle.USER_SYSTEM);
} catch (Exception e) {
// As above, probably racing with uninstall.
return;
@@ -5964,6 +5975,11 @@ public final class ActivityManagerService extends ActivityManagerNative
return needRestart;
}
+ private final void processContentProviderPublishTimedOutLocked(ProcessRecord app) {
+ cleanupAppInLaunchingProvidersLocked(app, true);
+ removeProcessLocked(app, false, true, "timeout publishing content providers");
+ }
+
private final void processStartTimedOutLocked(ProcessRecord app) {
final int pid = app.pid;
boolean gone = false;
@@ -5990,7 +6006,7 @@ public final class ActivityManagerService extends ActivityManagerNative
mBatteryStatsService.removeIsolatedUid(app.uid, app.info.uid);
}
// Take care of any launching providers waiting for this process.
- checkAppInLaunchingProvidersLocked(app, true);
+ cleanupAppInLaunchingProvidersLocked(app, true);
// Take care of any services that are waiting for the process.
mServices.processStartTimedOutLocked(app);
app.kill("start timeout", true);
@@ -6086,6 +6102,12 @@ public final class ActivityManagerService extends ActivityManagerNative
boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);
List<ProviderInfo> providers = normalMode ? generateApplicationProvidersLocked(app) : null;
+ if (providers != null && checkAppInLaunchingProvidersLocked(app)) {
+ Message msg = mHandler.obtainMessage(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG);
+ msg.obj = app;
+ mHandler.sendMessageDelayed(msg, CONTENT_PROVIDER_PUBLISH_TIMEOUT);
+ }
+
if (!normalMode) {
Slog.i(TAG, "Launching preboot mode app: " + app);
}
@@ -8645,14 +8667,14 @@ public final class ActivityManagerService extends ActivityManagerNative
}
if (task.mResizeable != resizeable) {
task.mResizeable = resizeable;
- mStackSupervisor.ensureActivitiesVisibleLocked(null, 0);
+ mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
mStackSupervisor.resumeTopActivitiesLocked();
}
}
}
@Override
- public void resizeTask(int taskId, Rect bounds) {
+ public void resizeTask(int taskId, Rect bounds, int resizeMode) {
enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
"resizeTask()");
long ident = Binder.clearCallingIdentity();
@@ -8663,7 +8685,7 @@ public final class ActivityManagerService extends ActivityManagerNative
Slog.w(TAG, "resizeTask: taskId=" + taskId + " not found");
return;
}
- mStackSupervisor.resizeTaskLocked(task, bounds);
+ mStackSupervisor.resizeTaskLocked(task, bounds, resizeMode);
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -9053,6 +9075,35 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
+ /**
+ * Moves the input task to the docked stack.
+ *
+ * @param taskId Id of task to move.
+ * @param createMode The mode the docked stack should be created in if it doesn't exist
+ * already. See
+ * {@link android.app.ActivityManager#DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT}
+ * and
+ * {@link android.app.ActivityManager#DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT}
+ * @param toTop If the task and stack should be moved to the top.
+ */
+ @Override
+ public void moveTaskToDockedStack(int taskId, int createMode, boolean toTop) {
+ enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
+ "moveTaskToDockedStack()");
+ synchronized (this) {
+ long ident = Binder.clearCallingIdentity();
+ try {
+ if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToDockedStack: moving task=" + taskId
+ + " to createMode=" + createMode + " toTop=" + toTop);
+ mWindowManager.setDockedStackCreateMode(createMode);
+ mStackSupervisor.moveTaskToStackLocked(
+ taskId, DOCKED_STACK_ID, toTop, !FORCE_FOCUS);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
@Override
public void resizeStack(int stackId, Rect bounds) {
enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
@@ -9060,7 +9111,7 @@ public final class ActivityManagerService extends ActivityManagerNative
long ident = Binder.clearCallingIdentity();
try {
synchronized (this) {
- mStackSupervisor.resizeStackLocked(stackId, bounds);
+ mStackSupervisor.resizeStackLocked(stackId, bounds, !PRESERVE_WINDOWS);
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -9343,7 +9394,7 @@ public final class ActivityManagerService extends ActivityManagerNative
(ProviderInfo)providers.get(i);
boolean singleton = isSingleton(cpi.processName, cpi.applicationInfo,
cpi.name, cpi.flags);
- if (singleton && UserHandle.getUserId(app.uid) != UserHandle.USER_OWNER) {
+ if (singleton && UserHandle.getUserId(app.uid) != UserHandle.USER_SYSTEM) {
// This is a singleton provider, but a user besides the
// default user is asking to initialize a process it runs
// in... well, no, it doesn't actually run in this process,
@@ -9565,7 +9616,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
- private final ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
+ private ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
String name, IBinder token, boolean stable, int userId) {
ContentProviderRecord cpr;
ContentProviderConnection conn = null;
@@ -9593,14 +9644,14 @@ public final class ActivityManagerService extends ActivityManagerNative
cpr = mProviderMap.getProviderByName(name, userId);
// If that didn't work, check if it exists for user 0 and then
// verify that it's a singleton provider before using it.
- if (cpr == null && userId != UserHandle.USER_OWNER) {
- cpr = mProviderMap.getProviderByName(name, UserHandle.USER_OWNER);
+ if (cpr == null && userId != UserHandle.USER_SYSTEM) {
+ cpr = mProviderMap.getProviderByName(name, UserHandle.USER_SYSTEM);
if (cpr != null) {
cpi = cpr.info;
if (isSingleton(cpi.processName, cpi.applicationInfo,
cpi.name, cpi.flags)
&& isValidSingletonCall(r.uid, cpi.applicationInfo.uid)) {
- userId = UserHandle.USER_OWNER;
+ userId = UserHandle.USER_SYSTEM;
checkCrossUser = false;
} else {
cpr = null;
@@ -9693,7 +9744,6 @@ public final class ActivityManagerService extends ActivityManagerNative
Binder.restoreCallingIdentity(origId);
}
- boolean singleton;
if (!providerRunning) {
try {
checkTime(startTime, "getContentProviderImpl: before resolveContentProvider");
@@ -9710,11 +9760,11 @@ public final class ActivityManagerService extends ActivityManagerNative
// (it's a call within the same user || the provider is a
// privileged app)
// Then allow connecting to the singleton provider
- singleton = isSingleton(cpi.processName, cpi.applicationInfo,
+ boolean singleton = isSingleton(cpi.processName, cpi.applicationInfo,
cpi.name, cpi.flags)
&& isValidSingletonCall(r.uid, cpi.applicationInfo.uid);
if (singleton) {
- userId = UserHandle.USER_OWNER;
+ userId = UserHandle.USER_SYSTEM;
}
cpi.applicationInfo = getAppInfoForUser(cpi.applicationInfo, userId);
checkTime(startTime, "getContentProviderImpl: got app info for user");
@@ -10022,7 +10072,7 @@ public final class ActivityManagerService extends ActivityManagerNative
final long origId = Binder.clearCallingIdentity();
final int N = providers.size();
- for (int i=0; i<N; i++) {
+ for (int i = 0; i < N; i++) {
ContentProviderHolder src = providers.get(i);
if (src == null || src.info == null || src.provider == null) {
continue;
@@ -10037,15 +10087,20 @@ public final class ActivityManagerService extends ActivityManagerNative
mProviderMap.putProviderByName(names[j], dst);
}
- int NL = mLaunchingProviders.size();
+ int launchingCount = mLaunchingProviders.size();
int j;
- for (j=0; j<NL; j++) {
+ boolean wasInLaunchingProviders = false;
+ for (j = 0; j < launchingCount; j++) {
if (mLaunchingProviders.get(j) == dst) {
mLaunchingProviders.remove(j);
+ wasInLaunchingProviders = true;
j--;
- NL--;
+ launchingCount--;
}
}
+ if (wasInLaunchingProviders) {
+ mHandler.removeMessages(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG, r);
+ }
synchronized (dst) {
dst.provider = src.provider;
dst.proc = r;
@@ -10312,7 +10367,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
final ProcessRecord r = new ProcessRecord(stats, info, proc, uid);
if (!mBooted && !mBooting
- && userId == UserHandle.USER_OWNER
+ && userId == UserHandle.USER_SYSTEM
&& (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) {
r.persistent = true;
}
@@ -11135,7 +11190,7 @@ public final class ActivityManagerService extends ActivityManagerNative
final boolean translucentChanged = r.changeWindowTranslucency(true);
if (translucentChanged) {
r.task.stack.releaseBackgroundResources(r);
- mStackSupervisor.ensureActivitiesVisibleLocked(null, 0);
+ mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
}
mWindowManager.setAppFullscreen(token, true);
return translucentChanged;
@@ -11163,7 +11218,7 @@ public final class ActivityManagerService extends ActivityManagerNative
if (translucentChanged) {
r.task.stack.convertActivityToTranslucent(r);
}
- mStackSupervisor.ensureActivitiesVisibleLocked(null, 0);
+ mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
mWindowManager.setAppFullscreen(token, false);
return translucentChanged;
}
@@ -11769,12 +11824,12 @@ public final class ActivityManagerService extends ActivityManagerNative
}
private boolean deliverPreBootCompleted(final Runnable onFinishCallback,
- ArrayList<ComponentName> doneReceivers, int userId) {
+ ArrayList<ComponentName> doneReceivers) {
Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
List<ResolveInfo> ris = null;
try {
ris = AppGlobals.getPackageManager().queryIntentReceivers(
- intent, null, 0, userId);
+ intent, null, 0, UserHandle.USER_SYSTEM);
} catch (RemoteException e) {
}
if (ris == null) {
@@ -11788,22 +11843,18 @@ public final class ActivityManagerService extends ActivityManagerNative
}
intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
- // For User 0, load the version number. When delivering to a new user, deliver
- // to all receivers.
- if (userId == UserHandle.USER_OWNER) {
- ArrayList<ComponentName> lastDoneReceivers = readLastDonePreBootReceivers();
- for (int i=0; i<ris.size(); i++) {
- ActivityInfo ai = ris.get(i).activityInfo;
- ComponentName comp = new ComponentName(ai.packageName, ai.name);
- if (lastDoneReceivers.contains(comp)) {
- // We already did the pre boot receiver for this app with the current
- // platform version, so don't do it again...
- ris.remove(i);
- i--;
- // ...however, do keep it as one that has been done, so we don't
- // forget about it when rewriting the file of last done receivers.
- doneReceivers.add(comp);
- }
+ ArrayList<ComponentName> lastDoneReceivers = readLastDonePreBootReceivers();
+ for (int i=0; i<ris.size(); i++) {
+ ActivityInfo ai = ris.get(i).activityInfo;
+ ComponentName comp = new ComponentName(ai.packageName, ai.name);
+ if (lastDoneReceivers.contains(comp)) {
+ // We already did the pre boot receiver for this app with the current
+ // platform version, so don't do it again...
+ ris.remove(i);
+ i--;
+ // ...however, do keep it as one that has been done, so we don't
+ // forget about it when rewriting the file of last done receivers.
+ doneReceivers.add(comp);
}
}
@@ -11811,9 +11862,8 @@ public final class ActivityManagerService extends ActivityManagerNative
return false;
}
- // If primary user, send broadcast to all available users, else just to userId
- final int[] users = userId == UserHandle.USER_OWNER ? getUsersLocked()
- : new int[] { userId };
+ // TODO: can we still do this with per user encryption?
+ final int[] users = getUsersLocked();
if (users.length <= 0) {
return false;
}
@@ -11864,7 +11914,7 @@ public final class ActivityManagerService extends ActivityManagerNative
writeLastDonePreBootReceivers(doneReceivers);
systemReady(goingCallback);
}
- }, doneReceivers, UserHandle.USER_OWNER);
+ }, doneReceivers);
if (mWaitingUpdate) {
return;
@@ -15716,7 +15766,7 @@ public final class ActivityManagerService extends ActivityManagerNative
app.pubProviders.clear();
// Take care of any launching providers waiting for this process.
- if (checkAppInLaunchingProvidersLocked(app, false)) {
+ if (cleanupAppInLaunchingProvidersLocked(app, false)) {
restart = true;
}
@@ -15838,7 +15888,17 @@ public final class ActivityManagerService extends ActivityManagerNative
return false;
}
- boolean checkAppInLaunchingProvidersLocked(ProcessRecord app, boolean alwaysBad) {
+ boolean checkAppInLaunchingProvidersLocked(ProcessRecord app) {
+ for (int i = mLaunchingProviders.size() - 1; i >= 0; i--) {
+ ContentProviderRecord cpr = mLaunchingProviders.get(i);
+ if (cpr.launchingApp == app) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ boolean cleanupAppInLaunchingProvidersLocked(ProcessRecord app, boolean alwaysBad) {
// Look through the content providers we are waiting to have launched,
// and if any run in this process then either schedule a restart of
// the process or kill the client waiting for it if this process has
@@ -17457,6 +17517,15 @@ public final class ActivityManagerService extends ActivityManagerNative
}
@Override
+ public void suppressResizeConfigChanges(boolean suppress) throws RemoteException {
+ enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
+ "suppressResizeConfigChanges()");
+ synchronized (this) {
+ mSuppressResizeConfigChanges = suppress;
+ }
+ }
+
+ @Override
public void updatePersistentConfiguration(Configuration values) {
enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
"updateConfiguration()");
@@ -17633,10 +17702,11 @@ public final class ActivityManagerService extends ActivityManagerNative
}
if (starting != null) {
- kept = mainStack.ensureActivityConfigurationLocked(starting, changes);
+ kept = mainStack.ensureActivityConfigurationLocked(starting, changes, false);
// And we need to make sure at this point that all other activities
// are made visible with the correct configuration.
- mStackSupervisor.ensureActivitiesVisibleLocked(starting, changes);
+ mStackSupervisor.ensureActivitiesVisibleLocked(starting, changes,
+ !PRESERVE_WINDOWS);
}
}
@@ -20107,7 +20177,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
if ((userInfo.flags&UserInfo.FLAG_INITIALIZED) == 0) {
- if (userId != UserHandle.USER_OWNER) {
+ if (userId != UserHandle.USER_SYSTEM) {
Intent intent = new Intent(Intent.ACTION_USER_INITIALIZE);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
broadcastIntentLocked(null, null, intent, null,
@@ -20345,7 +20415,7 @@ public final class ActivityManagerService extends ActivityManagerNative
for (int i = 0; i < num; i++) {
Integer oldUserId = mUserLru.get(i);
UserState oldUss = mStartedUsers.get(oldUserId);
- if (oldUserId == UserHandle.USER_OWNER || oldUserId == mCurrentUserId
+ if (oldUserId == UserHandle.USER_SYSTEM || oldUserId == mCurrentUserId
|| oldUss.mState == UserState.STATE_STOPPING
|| oldUss.mState == UserState.STATE_SHUTDOWN) {
continue;
@@ -20430,8 +20500,12 @@ public final class ActivityManagerService extends ActivityManagerNative
i++;
continue;
}
- if (oldUserId == UserHandle.USER_OWNER || oldUserId == mCurrentUserId) {
- // Owner and current can't be stopped, but count as running.
+ if (oldUserId == UserHandle.USER_SYSTEM || oldUserId == mCurrentUserId) {
+ // Owner/System user and current user can't be stopped. We count it as running
+ // when it is not a pure system user.
+ if (UserInfo.isSystemOnly(oldUserId)) {
+ num--;
+ }
i++;
continue;
}
@@ -20454,8 +20528,8 @@ public final class ActivityManagerService extends ActivityManagerNative
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
- if (userId < 0 || userId == UserHandle.USER_OWNER) {
- throw new IllegalArgumentException("Can't stop primary user " + userId);
+ if (userId < 0 || userId == UserHandle.USER_SYSTEM) {
+ throw new IllegalArgumentException("Can't stop system user " + userId);
}
enforceShellRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES, userId);
synchronized (this) {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 032b73101173..a796ea7d4ab5 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -17,8 +17,11 @@
package com.android.server.am;
import static android.app.ActivityManager.DOCKED_STACK_ID;
+import static android.app.ActivityManager.FIRST_STATIC_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.LAST_STATIC_STACK_ID;
import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
import static com.android.server.am.ActivityManagerDebugConfig.*;
@@ -27,10 +30,11 @@ import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
import static com.android.server.am.ActivityStackSupervisor.MOVING;
+import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
import android.graphics.Rect;
import android.util.ArraySet;
-import android.view.IApplicationToken;
+
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.content.ReferrerIntent;
import com.android.internal.os.BatteryStatsImpl;
@@ -525,21 +529,15 @@ final class ActivityStack {
* */
void moveToFront(String reason, TaskRecord task) {
if (isAttached()) {
- final boolean homeStack = isHomeStack()
- || (mActivityContainer.mParentActivity != null
- && mActivityContainer.mParentActivity.isHomeActivity());
- ActivityStack lastFocusStack = null;
- if (!homeStack) {
- // Need to move this stack to the front before calling
- // {@link ActivityStackSupervisor#moveHomeStack} below.
- lastFocusStack = mStacks.get(mStacks.size() - 1);
- mStacks.remove(this);
- mStacks.add(this);
- }
- // TODO(multi-display): Focus stack currently adjusted in call to move home stack.
- // Needs to also work if focus is moving to the non-home display.
+ final ActivityStack lastFocusStack = mStacks.get(mStacks.size() - 1);
+ // Need to move this stack to the front before calling
+ // {@link ActivityStackSupervisor#setFocusStack} below.
+ mStacks.remove(this);
+ mStacks.add(this);
+
+ // TODO(multi-display): Needs to also work if focus is moving to the non-home display.
if (isOnHomeDisplay()) {
- mStackSupervisor.moveHomeStack(homeStack, reason, lastFocusStack);
+ mStackSupervisor.setFocusStack(reason, lastFocusStack);
}
if (task != null) {
insertTaskAtTop(task, null);
@@ -812,7 +810,7 @@ final class ActivityStack {
}
void goToSleep() {
- ensureActivitiesVisibleLocked(null, 0);
+ ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
// Make sure any stopped but visible activities are now sleeping.
// This ensures that the activity's onStop() is called.
@@ -1278,28 +1276,27 @@ final class ActivityStack {
return false;
}
- /** Return true if this stack is hidden by the presence of a docked stack. */
- private boolean isHiddenByDockedStack() {
- final ActivityStack dockedStack = mStackSupervisor.getStack(DOCKED_STACK_ID);
- if (dockedStack != null) {
- final int dockedStackIndex = mStacks.indexOf(dockedStack);
- final int stackIndex = mStacks.indexOf(this);
- if (dockedStackIndex > stackIndex) {
- // Fullscreen stacks or stacks with fullscreen task below the docked stack are not
- // visible. We do this so we don't have the 2 stacks and their tasks overlap.
- if (mFullscreen) {
- return true;
- }
+ private boolean hasTranslucentActivity(ActivityStack stack) {
+ final ArrayList<TaskRecord> tasks = stack.getAllTasks();
+ for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
+ final TaskRecord task = tasks.get(taskNdx);
+ final ArrayList<ActivityRecord> activities = task.mActivities;
+ for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+ final ActivityRecord r = activities.get(activityNdx);
- // We need to also check the tasks in the stack because they can be fullscreen
- // even though their stack isn't due to their root activity not been resizeable
- // (i.e. doesn't support multi-window mode).
- if (hasFullscreenTask()) {
- return true;
+ // Conditions for an activity to obscure the stack we're
+ // examining:
+ // 1. Not Finishing AND Visible AND:
+ // 2. Either:
+ // - Full Screen Activity OR
+ // - On top of Home and our stack is NOT home
+ if (!r.finishing && r.visible && (r.fullscreen ||
+ (!isHomeStack() && r.frontOfTask && task.isOverHomeStack()))) {
+ return false;
}
}
}
- return false;
+ return true;
}
/** Returns true if the stack is considered visible. */
@@ -1320,54 +1317,64 @@ final class ActivityStack {
return false;
}
- if (isHiddenByDockedStack()) {
+ final ActivityStack focusedStack = mStackSupervisor.getFocusedStack();
+ final int focusedStackId = focusedStack.mStackId;
+
+ if (mStackId == DOCKED_STACK_ID) {
+ // Docked stack is always visible, except in the case where the home activity
+ // is the top running activity in the focused home stack.
+ if (focusedStackId != HOME_STACK_ID) {
+ return true;
+ }
+ ActivityRecord topHomeActivity = focusedStack.topRunningActivityLocked(null);
+ return topHomeActivity == null || !topHomeActivity.isHomeActivity();
+ }
+
+ final int belowFocusedIndex = mStacks.indexOf(focusedStack) - 1;
+ if (focusedStackId == DOCKED_STACK_ID && stackIndex == belowFocusedIndex) {
+ // Stacks directly behind the docked stack are always visible.
+ return true;
+ }
+
+ if (focusedStackId == FULLSCREEN_WORKSPACE_STACK_ID
+ && hasTranslucentActivity(focusedStack)) {
+ // Stacks behind the fullscreen stack with a translucent activity are always
+ // visible so they can act as a backdrop to the translucent activity.
+ // For example, dialog activities
+ if (stackIndex == belowFocusedIndex) {
+ return true;
+ }
+ if (belowFocusedIndex >= 0) {
+ final ActivityStack stack = mStacks.get(belowFocusedIndex);
+ if (stack.mStackId == DOCKED_STACK_ID && stackIndex == (belowFocusedIndex - 1)) {
+ // The stack behind the docked stack is also visible so we can have a complete
+ // backdrop to the translucent activity when the docked stack is up.
+ return true;
+ }
+ }
+ }
+
+ if (mStackId >= FIRST_STATIC_STACK_ID && mStackId <= LAST_STATIC_STACK_ID) {
+ // Visibility of any static stack should have been determined by the conditions above.
return false;
}
- /**
- * Start at the task above this one and go up, looking for a visible
- * fullscreen activity, or a translucent activity that requested the
- * wallpaper to be shown behind it.
- */
for (int i = stackIndex + 1; i < mStacks.size(); i++) {
final ActivityStack stack = mStacks.get(i);
- final ArrayList<TaskRecord> tasks = stack.getAllTasks();
if (!stack.mFullscreen && !stack.hasFullscreenTask()) {
continue;
}
if (stack.mStackId == FREEFORM_WORKSPACE_STACK_ID
- || stack.mStackId == HOME_STACK_ID) {
- // The freeform and home stacks can't have any other stack visible behind them
- // when they are fullscreen since they act as base/cut-off points for visibility.
- // NOTE: we don't cut-off at the FULLSCREEN_WORKSPACE_STACK_ID because the home
- // stack sometimes needs to be visible behind it when it is displaying a dialog
- // activity. We let it fall through to the logic below to determine visibility.
+ || stack.mStackId == HOME_STACK_ID
+ || stack.mStackId == FULLSCREEN_WORKSPACE_STACK_ID) {
+ // These stacks can't have any dynamic stacks visible behind them.
return false;
}
- for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
- final TaskRecord task = tasks.get(taskNdx);
- // task above isn't fullscreen, so, we assume we're still visible.
- if (!task.mFullscreen) {
- continue;
- }
- final ArrayList<ActivityRecord> activities = task.mActivities;
- for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
- final ActivityRecord r = activities.get(activityNdx);
-
- // Conditions for an activity to obscure the stack we're
- // examining:
- // 1. Not Finishing AND Visible AND:
- // 2. Either:
- // - Full Screen Activity OR
- // - On top of Home and our stack is NOT home
- if (!r.finishing && r.visible && (r.fullscreen ||
- (!isHomeStack() && r.frontOfTask && task.isOverHomeStack()))) {
- return false;
- }
- }
+ if (!hasTranslucentActivity(stack)) {
+ return false;
}
}
@@ -1378,7 +1385,8 @@ final class ActivityStack {
* Make sure that all activities that need to be visible (that is, they
* currently can be seen by the user) actually are.
*/
- final void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges) {
+ final void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges,
+ boolean preserveWindows) {
ActivityRecord top = topRunningActivityLocked(null);
if (top == null) {
return;
@@ -1400,16 +1408,14 @@ final class ActivityStack {
// If the top activity is not fullscreen, then we need to
// make sure any activities under it are now visible.
boolean aboveTop = true;
- boolean behindFullscreen = !isStackVisibleLocked();
+ final boolean stackInvisible = !isStackVisibleLocked();
+ boolean behindFullscreenActivity = stackInvisible;
boolean noStackActivityResumed = (isInStackLocked(starting) == null);
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
final TaskRecord task = mTaskHistory.get(taskNdx);
final ArrayList<ActivityRecord> activities = task.mActivities;
- // Set to true if an activity in this task is fullscreen thereby hiding other
- // activities in the same task. Initialized to the same value as behindFullscreen
- // which represent if the entire task/stack is behind another fullscreen task/stack.
- boolean behindFullscreenActivity = behindFullscreen;
+
for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
final ActivityRecord r = activities.get(activityNdx);
if (r.finishing) {
@@ -1429,7 +1435,7 @@ final class ActivityStack {
// First: if this is not the current activity being started, make
// sure it matches the current configuration.
if (r != starting) {
- ensureActivityConfigurationLocked(r, 0);
+ ensureActivityConfigurationLocked(r, 0, preserveWindows);
}
if (r.app == null || r.app.thread == null) {
@@ -1507,18 +1513,18 @@ final class ActivityStack {
// At this point, nothing else needs to be shown in this task.
behindFullscreenActivity = true;
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Fullscreen: at " + r
- + " behindFullscreen=" + behindFullscreen
+ + " stackInvisible=" + stackInvisible
+ " behindFullscreenActivity=" + behindFullscreenActivity);
} else if (!isHomeStack() && r.frontOfTask && task.isOverHomeStack()) {
behindFullscreenActivity = true;
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Showing home: at " + r
- + " behindFullscreen=" + behindFullscreen
+ + " stackInvisible=" + stackInvisible
+ " behindFullscreenActivity=" + behindFullscreenActivity);
}
} else {
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
"Make invisible? " + r + " finishing=" + r.finishing
- + " state=" + r.state + " behindFullscreen=" + behindFullscreen
+ + " state=" + r.state + " stackInvisible=" + stackInvisible
+ " behindFullscreenActivity=" + behindFullscreenActivity);
// Now for any activities that aren't visible to the user, make
// sure they no longer are keeping the screen frozen.
@@ -1566,9 +1572,12 @@ final class ActivityStack {
}
}
}
- // Factoring if the previous task is fullscreen there by affecting the visibility of
- // task behind it.
- behindFullscreen |= task.mFullscreen;
+ if (mStackId == FREEFORM_WORKSPACE_STACK_ID) {
+ // The visibility of tasks and the activities they contain in freeform stack are
+ // determined individually unlike other stacks where the visibility or fullscreen
+ // status of an activity in a previous task affects other.
+ behindFullscreenActivity = stackInvisible;
+ }
}
if (mTranslucentActivityWaiting != null &&
@@ -2335,7 +2344,7 @@ final class ActivityStack {
// Don't do a starting window for mLaunchTaskBehind. More importantly make sure we
// tell WindowManager that r is visible even though it is at the back of the stack.
mWindowManager.setAppVisibility(r.appToken, true);
- ensureActivitiesVisibleLocked(null, 0);
+ ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
} else if (SHOW_APP_STARTING_PREVIEW && doShow) {
// Figure out if we are transitioning from another activity that is
// "has the same starting icon" as the next one. This allows the
@@ -3494,7 +3503,7 @@ final class ActivityStack {
final boolean destroyActivityLocked(ActivityRecord r, boolean removeFromApp, String reason) {
if (DEBUG_SWITCH || DEBUG_CLEANUP) Slog.v(TAG_SWITCH,
"Removing activity from " + reason + ": token=" + r
- + ", app=" + (r.app != null ? r.app.processName : "(null)"));
+ + ", app=" + (r.app != null ? r.app.processName : "(null)"));
EventLog.writeEvent(EventLogTags.AM_DESTROY_ACTIVITY,
r.userId, System.identityHashCode(r),
r.task.taskId, r.shortComponentName, reason);
@@ -3971,7 +3980,8 @@ final class ActivityStack {
* for whatever reason. Ensures the HistoryRecord is updated with the
* correct configuration and all other bookkeeping is handled.
*/
- final boolean ensureActivityConfigurationLocked(ActivityRecord r, int globalChanges) {
+ final boolean ensureActivityConfigurationLocked(ActivityRecord r, int globalChanges,
+ boolean preserveWindow) {
if (mConfigWillChange) {
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
"Skipping config check (will change): " + r);
@@ -4016,6 +4026,11 @@ final class ActivityStack {
return true;
}
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
+ "Configuration changes for " + r + " ; taskChanges="
+ + Configuration.configurationDiffToString(taskChanges) + ", allChanges="
+ + Configuration.configurationDiffToString(changes));
+
// If the activity isn't currently running, just leave the new
// configuration and it will pick that up next time it starts.
if (r.app == null || r.app.thread == null) {
@@ -4056,12 +4071,14 @@ final class ActivityStack {
// "restart!".
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
"Config is relaunching resumed " + r);
- relaunchActivityLocked(r, r.configChangeFlags, true);
+ relaunchActivityLocked(r, r.configChangeFlags, true,
+ preserveWindow && isResizeOnlyChange(changes));
r.configChangeFlags = 0;
} else {
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
"Config is relaunching non-resumed " + r);
- relaunchActivityLocked(r, r.configChangeFlags, false);
+ relaunchActivityLocked(r, r.configChangeFlags, false,
+ preserveWindow && isResizeOnlyChange(changes));
r.configChangeFlags = 0;
}
@@ -4154,7 +4171,17 @@ final class ActivityStack {
return taskChanges;
}
- private boolean relaunchActivityLocked(ActivityRecord r, int changes, boolean andResume) {
+ private static boolean isResizeOnlyChange(int change) {
+ return (change & ~(ActivityInfo.CONFIG_SCREEN_SIZE
+ | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE | ActivityInfo.CONFIG_ORIENTATION)) == 0;
+ }
+
+ private void relaunchActivityLocked(
+ ActivityRecord r, int changes, boolean andResume, boolean preserveWindow) {
+ if (mService.mSuppressResizeConfigChanges && preserveWindow) {
+ return;
+ }
+
List<ResultInfo> results = null;
List<ReferrerIntent> newIntents = null;
if (andResume) {
@@ -4163,7 +4190,7 @@ final class ActivityStack {
}
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
"Relaunching: " + r + " with results=" + results + " newIntents=" + newIntents
- + " andResume=" + andResume);
+ + " andResume=" + andResume + " preserveWindow=" + preserveWindow);
EventLog.writeEvent(andResume ? EventLogTags.AM_RELAUNCH_RESUME_ACTIVITY
: EventLogTags.AM_RELAUNCH_ACTIVITY, r.userId, System.identityHashCode(r),
r.task.taskId, r.shortComponentName);
@@ -4178,7 +4205,7 @@ final class ActivityStack {
r.forceNewConfig = false;
r.app.thread.scheduleRelaunchActivity(r.appToken, results, newIntents, changes,
!andResume, new Configuration(mService.mConfiguration),
- new Configuration(r.task.mOverrideConfig));
+ new Configuration(r.task.mOverrideConfig), preserveWindow);
// Note: don't need to call pauseIfSleepingLocked() here, because
// the caller will only pass in 'andResume' if this activity is
// currently resumed, which implies we aren't sleeping.
@@ -4194,8 +4221,6 @@ final class ActivityStack {
mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
r.state = ActivityState.PAUSED;
}
-
- return true;
}
boolean willActivityBeVisibleLocked(IBinder token) {
@@ -4520,18 +4545,17 @@ final class ActivityStack {
if (mTaskHistory.isEmpty()) {
if (DEBUG_STACK) Slog.i(TAG_STACK, "removeTask: removing stack=" + this);
- final boolean notHomeStack = !isHomeStack();
if (isOnHomeDisplay()) {
String myReason = reason + " leftTaskHistoryEmpty";
if (mFullscreen || !adjustFocusToNextVisibleStackLocked(null, myReason)) {
- mStackSupervisor.moveHomeStack(notHomeStack, myReason);
+ mStackSupervisor.moveHomeStackToFront(myReason);
}
}
if (mStacks != null) {
mStacks.remove(this);
mStacks.add(0, this);
}
- if (notHomeStack) {
+ if (!isHomeStack()) {
mActivityContainer.onTaskListEmptyLocked();
}
}
@@ -4548,6 +4572,8 @@ final class ActivityStack {
addTask(task, toTop, false);
if (mTaskPositioner != null) {
mTaskPositioner.updateDefaultBounds(task, mTaskHistory, info.initialLayout);
+ } else if (mBounds != null && task.mResizeable) {
+ task.updateOverrideConfiguration(mBounds);
}
return task;
}
@@ -4590,7 +4616,7 @@ final class ActivityStack {
r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
(r.info.flags & ActivityInfo.FLAG_SHOW_FOR_ALL_USERS) != 0, r.userId,
r.info.configChanges, task.voiceSession != null, r.mLaunchTaskBehind,
- bounds, task.mOverrideConfig);
+ bounds, task.mOverrideConfig, !r.isHomeActivity());
r.taskConfigOverride = task.mOverrideConfig;
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 8ab4ae59a201..ed92579dc21e 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;
@@ -175,6 +177,9 @@ public final class ActivityStackSupervisor implements DisplayListener {
// should be created if it doesn't exist already.
private static final boolean CREATE_IF_NEEDED = true;
+ // Used to indicate that windows of activities should be preserved during the resize.
+ static final boolean PRESERVE_WINDOWS = true;
+
// Used to indicate if an object (e.g. task) should be moved/created
// at the top of its container (e.g. stack).
static final boolean ON_TOP = true;
@@ -189,6 +194,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
// Activity actions an app cannot start if it uses a permission which is not granted.
private static final ArrayMap<String, String> ACTION_TO_RUNTIME_PERMISSION =
new ArrayMap<>();
+
static {
ACTION_TO_RUNTIME_PERMISSION.put(MediaStore.ACTION_IMAGE_CAPTURE,
Manifest.permission.CAMERA);
@@ -464,35 +470,22 @@ public final class ActivityStackSupervisor implements DisplayListener {
return stack == mFocusedStack;
}
- void moveHomeStack(boolean toFront, String reason) {
- moveHomeStack(toFront, reason, null);
- }
-
- void moveHomeStack(boolean toFront, String reason, ActivityStack lastFocusedStack) {
+ void setFocusStack(String reason, ActivityStack lastFocusedStack) {
ArrayList<ActivityStack> stacks = mHomeStack.mStacks;
final int topNdx = stacks.size() - 1;
if (topNdx <= 0) {
return;
}
- // The home stack should either be at the top or bottom of the stack list.
- if ((toFront && (stacks.get(topNdx) != mHomeStack))
- || (!toFront && (stacks.get(0) != mHomeStack))) {
- if (DEBUG_STACK) Slog.d(TAG_STACK, "moveHomeTask: topStack old="
- + ((lastFocusedStack != null) ? lastFocusedStack : stacks.get(topNdx))
- + " new=" + mFocusedStack);
- stacks.remove(mHomeStack);
- stacks.add(toFront ? topNdx : 0, mHomeStack);
- }
-
+ final ActivityStack topStack = stacks.get(topNdx);
+ mFocusedStack = topStack;
if (lastFocusedStack != null) {
mLastFocusedStack = lastFocusedStack;
}
- mFocusedStack = stacks.get(topNdx);
- EventLog.writeEvent(EventLogTags.AM_HOME_STACK_MOVED,
- mCurrentUser, toFront ? 1 : 0, stacks.get(topNdx).getStackId(),
- mFocusedStack == null ? -1 : mFocusedStack.getStackId(), reason);
+ EventLogTags.writeAmFocusedStack(
+ mCurrentUser, mFocusedStack == null ? -1 : mFocusedStack.getStackId(),
+ mLastFocusedStack == null ? -1 : mLastFocusedStack.getStackId(), reason);
if (mService.mBooting || !mService.mBooted) {
final ActivityRecord r = topRunningActivityLocked();
@@ -502,6 +495,10 @@ public final class ActivityStackSupervisor implements DisplayListener {
}
}
+ void moveHomeStackToFront(String reason) {
+ mHomeStack.moveToFront(reason);
+ }
+
/** Returns true if the focus activity was adjusted to the home stack top activity. */
boolean moveHomeStackTaskToTop(int homeStackTaskType, String reason) {
if (homeStackTaskType == RECENTS_ACTIVITY_TYPE) {
@@ -660,7 +657,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
}
}
if (!didSomething) {
- ensureActivitiesVisibleLocked(null, 0);
+ ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
}
return didSomething;
}
@@ -1353,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) {
@@ -1803,8 +1799,11 @@ public final class ActivityStackSupervisor implements DisplayListener {
return container.mStack;
}
- if (mFocusedStack != mHomeStack && (!newTask ||
- mFocusedStack.mActivityContainer.isEligibleForNewTasks())) {
+ // The fullscreen stack is the only stack that can contain any task regardless of if
+ // the task is resizeable or not. So, we let the task go in the fullscreen task if it
+ // is the focus stack.
+ if (mFocusedStack.mStackId == FULLSCREEN_WORKSPACE_STACK_ID
+ && (!newTask || mFocusedStack.mActivityContainer.isEligibleForNewTasks())) {
if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
"computeStackFocus: Have a focused stack=" + mFocusedStack);
return mFocusedStack;
@@ -1823,7 +1822,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
}
// If there is no suitable dynamic stack then we figure out which static stack to use.
- int stackId = task != null ? task.getLaunchStackId() :
+ final int stackId = task != null ? task.getLaunchStackId() :
bounds != null ? FREEFORM_WORKSPACE_STACK_ID :
FULLSCREEN_WORKSPACE_STACK_ID;
stack = getStack(stackId, CREATE_IF_NEEDED, ON_TOP);
@@ -2629,7 +2628,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
}
mLaunchingActivity.release();
}
- ensureActivitiesVisibleLocked(null, 0);
+ ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
}
// Atomically retrieve all of the other things to do.
@@ -2859,7 +2858,8 @@ public final class ActivityStackSupervisor implements DisplayListener {
if (opts.hasBounds()) {
Rect bounds = opts.getBounds();
task.updateOverrideConfiguration(bounds);
- mWindowManager.resizeTask(task.taskId, bounds, task.mOverrideConfig, false);
+ mWindowManager.resizeTask(task.taskId, bounds, task.mOverrideConfig,
+ false /*relayout*/, false /*forced*/);
stackId = task.getLaunchStackId();
}
}
@@ -2962,39 +2962,39 @@ public final class ActivityStackSupervisor implements DisplayListener {
}
}
- void resizeStackLocked(int stackId, Rect bounds) {
+ void resizeStackLocked(int stackId, Rect bounds, boolean preserveWindows) {
final ActivityStack stack = getStack(stackId);
if (stack == null) {
Slog.w(TAG, "resizeStack: stackId " + stackId + " not found.");
return;
}
+ Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeStack_" + stackId);
+
ActivityRecord r = stack.topRunningActivityLocked(null);
- final boolean resizeTasks = r != null && r.task.mResizeable;
mTmpBounds.clear();
mTmpConfigs.clear();
- if (resizeTasks) {
- ArrayList<TaskRecord> tasks = stack.getAllTasks();
- for (int i = tasks.size() - 1; i >= 0; i--) {
- TaskRecord task = tasks.get(i);
+ ArrayList<TaskRecord> tasks = stack.getAllTasks();
+ for (int i = tasks.size() - 1; i >= 0; i--) {
+ TaskRecord task = tasks.get(i);
+ if (task.mResizeable) {
if (stack.mStackId == FREEFORM_WORKSPACE_STACK_ID) {
- // For freeform stack we don't adjust the size of the tasks to match that of
- // the stack, but we do try to make sure the tasks are still contained with the
- // bounds of the stack.
+ // For freeform stack we don't adjust the size of the tasks to match that
+ // of the stack, but we do try to make sure the tasks are still contained
+ // with the bounds of the stack.
tempRect2.set(task.mBounds);
fitWithinBounds(tempRect2, bounds);
task.updateOverrideConfiguration(tempRect2);
} else {
task.updateOverrideConfiguration(bounds);
}
-
- mTmpConfigs.put(task.taskId, task.mOverrideConfig);
- mTmpBounds.put(task.taskId, task.mBounds);
}
+
+ mTmpConfigs.put(task.taskId, task.mOverrideConfig);
+ mTmpBounds.put(task.taskId, task.mBounds);
}
- stack.mFullscreen = mWindowManager.resizeStack(stackId, bounds, resizeTasks, mTmpConfigs,
- mTmpBounds);
+ stack.mFullscreen = mWindowManager.resizeStack(stackId, bounds, mTmpConfigs, mTmpBounds);
if (stack.mStackId == DOCKED_STACK_ID) {
// Dock stack funness...Yay!
if (stack.mFullscreen) {
@@ -3003,11 +3003,10 @@ public final class ActivityStackSupervisor implements DisplayListener {
// docked stack tasks to the fullscreen stack.
for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) {
if (i != DOCKED_STACK_ID) {
- resizeStackLocked(i, null);
+ resizeStackLocked(i, null, preserveWindows);
}
}
- final ArrayList<TaskRecord> tasks = stack.getAllTasks();
final int count = tasks.size();
for (int i = 0; i < count; i++) {
moveTaskToStackLocked(tasks.get(i).taskId,
@@ -3035,33 +3034,40 @@ public final class ActivityStackSupervisor implements DisplayListener {
tempRect.right -= leftChange;
tempRect.top -= bottomChange;
tempRect.bottom -= topChange;
- resizeStackLocked(i, tempRect);
+ resizeStackLocked(i, tempRect, PRESERVE_WINDOWS);
}
}
}
-
}
+ // Since we are resizing the stack, all other operations should strive to preserve
+ // windows.
+ preserveWindows = true;
}
stack.setBounds(bounds);
if (r != null) {
- final boolean updated = stack.ensureActivityConfigurationLocked(r, 0);
+ final boolean updated = stack.ensureActivityConfigurationLocked(r, 0, preserveWindows);
// And we need to make sure at this point that all other activities
// are made visible with the correct configuration.
- ensureActivitiesVisibleLocked(r, 0);
+ ensureActivitiesVisibleLocked(r, 0, preserveWindows);
if (!updated) {
resumeTopActivitiesLocked(stack, null, null);
}
}
+
+ Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
- void resizeTaskLocked(TaskRecord task, Rect bounds) {
+ void resizeTaskLocked(TaskRecord task, Rect bounds, int resizeMode) {
if (!task.mResizeable) {
Slog.w(TAG, "resizeTask: task " + task + " not resizeable.");
return;
}
- if (task.mBounds != null && task.mBounds.equals(bounds)) {
+ // 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);
+ if (task.mBounds != null && task.mBounds.equals(bounds) && !forced) {
// Nothing to do here...
return;
}
@@ -3078,6 +3084,8 @@ public final class ActivityStackSupervisor implements DisplayListener {
return;
}
+ Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeTask_" + task.taskId);
+
// 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.
@@ -3088,7 +3096,8 @@ public final class ActivityStackSupervisor implements DisplayListener {
&& stackId != FREEFORM_WORKSPACE_STACK_ID && stackId != DOCKED_STACK_ID) {
stackId = FREEFORM_WORKSPACE_STACK_ID;
}
- if (stackId != task.stack.mStackId) {
+ final boolean changedStacks = stackId != task.stack.mStackId;
+ if (changedStacks) {
moveTaskToStackUncheckedLocked(task, stackId, ON_TOP, !FORCE_FOCUS, "resizeTask");
}
@@ -3101,24 +3110,19 @@ public final class ActivityStackSupervisor implements DisplayListener {
ActivityRecord r = task.topRunningActivityLocked(null);
if (r != null) {
final ActivityStack stack = task.stack;
- kept = stack.ensureActivityConfigurationLocked(r, 0);
+ 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);
+ ensureActivitiesVisibleLocked(r, 0, !PRESERVE_WINDOWS);
if (!kept) {
resumeTopActivitiesLocked(stack, null, null);
- // We are about to relaunch the activity because its configuration changed due
- // to 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. If we also changed
- // the stack to the fullscreen stack, i.e. maximized the window, we will animate
- // the transition.
- mWindowManager.setReplacingWindow(r.appToken,
- stackId == FULLSCREEN_WORKSPACE_STACK_ID /* animate */);
}
}
}
- mWindowManager.resizeTask(task.taskId, bounds, task.mOverrideConfig, kept);
+ mWindowManager.resizeTask(task.taskId, bounds, task.mOverrideConfig, kept, forced);
+
+ Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
ActivityStack createStackOnDisplay(int stackId, int displayId, boolean onTop) {
@@ -3205,7 +3209,13 @@ public final class ActivityStackSupervisor implements DisplayListener {
final boolean wasFocused = isFrontStack(task.stack) && (topRunningActivityLocked() == r);
final boolean wasResumed = wasFocused && (task.stack.mResumedActivity == r);
+ final boolean resizeable = task.mResizeable;
+ // Temporarily disable resizeablility of task we are moving. We don't want it to be resized
+ // if a docked stack is created below which will lead to the stack we are moving from and
+ // its resizeable tasks being resized.
+ task.mResizeable = false;
final ActivityStack stack = getStack(stackId, CREATE_IF_NEEDED, toTop);
+ task.mResizeable = resizeable;
mWindowManager.moveTaskToStack(task.taskId, stack.mStackId, toTop);
if (task.stack != null) {
task.stack.removeTask(task, reason, MOVING);
@@ -3235,22 +3245,32 @@ 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);
+ resizeTaskLocked(task, stack.mBounds, RESIZE_MODE_SYSTEM);
} else if (stackId == FREEFORM_WORKSPACE_STACK_ID
&& task.mBounds == null && task.mLastNonFullscreenBounds != null) {
- resizeTaskLocked(task, task.mLastNonFullscreenBounds);
+ resizeTaskLocked(task, task.mLastNonFullscreenBounds, RESIZE_MODE_SYSTEM);
} else if (stackId == DOCKED_STACK_ID) {
- resizeTaskLocked(task, stack.mBounds);
+ resizeTaskLocked(task, stack.mBounds, RESIZE_MODE_SYSTEM);
}
// The task might have already been running and its visibility needs to be synchronized with
// the visibility of the stack / windows.
- ensureActivitiesVisibleLocked(null, 0);
+ ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
resumeTopActivitiesLocked();
}
@@ -3270,7 +3290,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
stack.positionTask(task, position, stackChanged);
// The task might have already been running and its visibility needs to be synchronized with
// the visibility of the stack / windows.
- stack.ensureActivitiesVisibleLocked(null, 0);
+ stack.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
resumeTopActivitiesLocked();
}
@@ -3445,7 +3465,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
mService.updateUsageStats(r, true);
}
if (allResumedActivitiesComplete()) {
- ensureActivitiesVisibleLocked(null, 0);
+ ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
mWindowManager.executeAppTransition();
return true;
}
@@ -3531,14 +3551,15 @@ public final class ActivityStackSupervisor implements DisplayListener {
mHandler.obtainMessage(LAUNCH_TASK_BEHIND_COMPLETE, token).sendToTarget();
}
- void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges) {
+ void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges,
+ boolean preserveWindows) {
// First the front stacks. In case any are not fullscreen and are in front of home.
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
final int topStackNdx = stacks.size() - 1;
for (int stackNdx = topStackNdx; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = stacks.get(stackNdx);
- stack.ensureActivitiesVisibleLocked(starting, configChanges);
+ stack.ensureActivitiesVisibleLocked(starting, configChanges, preserveWindows);
}
}
}
@@ -3645,11 +3666,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
}
final boolean homeInFront = stack.isHomeStack();
if (stack.isOnHomeDisplay()) {
- moveHomeStack(homeInFront, "switchUserOnHomeDisplay");
- TaskRecord task = stack.topTask();
- if (task != null) {
- mWindowManager.moveTaskToTop(task.taskId);
- }
+ stack.moveToFront("switchUserOnHomeDisplay");
} else {
// Stack was moved to another display while user was swapped out.
resumeHomeStackTask(HOME_ACTIVITY_TYPE, null, "switchUserOnOtherDisplay");
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 335288da005b..62768c3b6475 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -171,12 +171,11 @@ public final class BatteryStatsService extends IBatteryStats.Stub
public void publish(Context context) {
mContext = context;
- ServiceManager.addService(BatteryStats.SERVICE_NAME, asBinder());
- mStats.setNumSpeedSteps(new PowerProfile(mContext).getNumSpeedSteps());
mStats.setRadioScanningTimeout(mContext.getResources().getInteger(
com.android.internal.R.integer.config_radioScanningTimeout)
* 1000L);
mStats.setPowerProfile(new PowerProfile(context));
+ ServiceManager.addService(BatteryStats.SERVICE_NAME, asBinder());
}
/**
diff --git a/services/core/java/com/android/server/am/CompatModePackages.java b/services/core/java/com/android/server/am/CompatModePackages.java
index 814e8b42e9d7..c36fd06f633b 100644
--- a/services/core/java/com/android/server/am/CompatModePackages.java
+++ b/services/core/java/com/android/server/am/CompatModePackages.java
@@ -17,6 +17,7 @@
package com.android.server.am;
import static com.android.server.am.ActivityManagerDebugConfig.*;
+import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
import java.io.File;
import java.io.FileInputStream;
@@ -344,10 +345,10 @@ public final class CompatModePackages {
}
if (starting != null) {
- stack.ensureActivityConfigurationLocked(starting, 0);
+ stack.ensureActivityConfigurationLocked(starting, 0, false);
// And we need to make sure at this point that all other activities
// are made visible with the correct configuration.
- stack.ensureActivitiesVisibleLocked(starting, 0);
+ stack.ensureActivitiesVisibleLocked(starting, 0, !PRESERVE_WINDOWS);
}
}
}
diff --git a/services/core/java/com/android/server/am/EventLogTags.logtags b/services/core/java/com/android/server/am/EventLogTags.logtags
index 9a645dfc6985..78b5f3333b2c 100644
--- a/services/core/java/com/android/server/am/EventLogTags.logtags
+++ b/services/core/java/com/android/server/am/EventLogTags.logtags
@@ -93,8 +93,8 @@ option java_package com.android.server.am
# Activity focused
30043 am_focused_activity (User|1|5),(Component Name|3)
-# Home Stack brought to front or rear
-30044 am_home_stack_moved (User|1|5),(To Front|1|5),(Top Stack Id|1|5),(Focused Stack Id|1|5),(Reason|3)
+# Stack focus
+30044 am_focused_stack (User|1|5),(Focused Stack Id|1|5),(Last Focused Stack Id|1|5),(Reason|3)
# Running pre boot receiver
30045 am_pre_boot (User|1|5),(Package|3)
diff --git a/services/core/java/com/android/server/am/ProviderMap.java b/services/core/java/com/android/server/am/ProviderMap.java
index ed8b1dd7fcd5..878c0e7aba50 100644
--- a/services/core/java/com/android/server/am/ProviderMap.java
+++ b/services/core/java/com/android/server/am/ProviderMap.java
@@ -211,7 +211,7 @@ public final class ProviderMap {
boolean doit, boolean evenPersistent, int userId,
ArrayList<ContentProviderRecord> result) {
boolean didSomething = false;
- if (userId == UserHandle.USER_ALL || userId == UserHandle.USER_OWNER) {
+ if (userId == UserHandle.USER_ALL || userId == UserHandle.USER_SYSTEM) {
didSomething = collectPackageProvidersLocked(packageName, filterByClasses,
doit, evenPersistent, mSingletonByClass, result);
}
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 8f10f083c0ff..43f5baab793f 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -1235,7 +1235,7 @@ final class TaskRecord {
if (stack == null
|| stack.mStackId == HOME_STACK_ID
|| stack.mStackId == FULLSCREEN_WORKSPACE_STACK_ID) {
- return null;
+ return (mResizeable && stack != null) ? stack.mBounds : null;
} else if (stack.mStackId == DOCKED_STACK_ID) {
return stack.mBounds;
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 1475f2f292cc..e49a7e49822c 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -1560,7 +1560,7 @@ public class AudioService extends IAudioService.Stub {
} finally {
Binder.restoreCallingIdentity(ident);
}
- return UserHandle.USER_OWNER;
+ return UserHandle.USER_SYSTEM;
}
// UI update and Broadcast Intent
@@ -2524,11 +2524,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 +2892,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) {
diff --git a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
index aca699152e02..5fd39c02a10a 100644
--- a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
+++ b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
@@ -18,6 +18,7 @@ package com.android.server.connectivity;
import static android.system.OsConstants.*;
+import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkUtils;
@@ -27,6 +28,7 @@ import android.system.ErrnoException;
import android.system.Os;
import android.system.StructTimeval;
import android.text.TextUtils;
+import android.util.Pair;
import com.android.internal.util.IndentingPrintWriter;
@@ -149,6 +151,8 @@ public class NetworkDiagnostics {
}
private final Map<InetAddress, Measurement> mIcmpChecks = new HashMap<>();
+ private final Map<Pair<InetAddress, InetAddress>, Measurement> mExplicitSourceIcmpChecks =
+ new HashMap<>();
private final Map<InetAddress, Measurement> mDnsUdpChecks = new HashMap<>();
private final String mDescription;
@@ -178,7 +182,11 @@ public class NetworkDiagnostics {
for (RouteInfo route : mLinkProperties.getRoutes()) {
if (route.hasGateway()) {
- prepareIcmpMeasurement(route.getGateway());
+ InetAddress gateway = route.getGateway();
+ prepareIcmpMeasurement(gateway);
+ if (route.isIPv6Default()) {
+ prepareExplicitSourceIcmpMeasurements(gateway);
+ }
}
}
for (InetAddress nameserver : mLinkProperties.getDnsServers()) {
@@ -213,6 +221,20 @@ public class NetworkDiagnostics {
}
}
+ private void prepareExplicitSourceIcmpMeasurements(InetAddress target) {
+ for (LinkAddress l : mLinkProperties.getLinkAddresses()) {
+ InetAddress source = l.getAddress();
+ if (source instanceof Inet6Address && l.isGlobalPreferred()) {
+ Pair<InetAddress, InetAddress> srcTarget = new Pair<>(source, target);
+ if (!mExplicitSourceIcmpChecks.containsKey(srcTarget)) {
+ Measurement measurement = new Measurement();
+ measurement.thread = new Thread(new IcmpCheck(source, target, measurement));
+ mExplicitSourceIcmpChecks.put(srcTarget, measurement);
+ }
+ }
+ }
+ }
+
private void prepareDnsMeasurement(InetAddress target) {
if (!mDnsUdpChecks.containsKey(target)) {
Measurement measurement = new Measurement();
@@ -222,13 +244,16 @@ public class NetworkDiagnostics {
}
private int totalMeasurementCount() {
- return mIcmpChecks.size() + mDnsUdpChecks.size();
+ return mIcmpChecks.size() + mExplicitSourceIcmpChecks.size() + mDnsUdpChecks.size();
}
private void startMeasurements() {
for (Measurement measurement : mIcmpChecks.values()) {
measurement.thread.start();
}
+ for (Measurement measurement : mExplicitSourceIcmpChecks.values()) {
+ measurement.thread.start();
+ }
for (Measurement measurement : mDnsUdpChecks.values()) {
measurement.thread.start();
}
@@ -261,6 +286,10 @@ public class NetworkDiagnostics {
pw.println(entry.getValue().toString());
}
}
+ for (Map.Entry<Pair<InetAddress, InetAddress>, Measurement> entry :
+ mExplicitSourceIcmpChecks.entrySet()) {
+ pw.println(entry.getValue().toString());
+ }
for (Map.Entry<InetAddress, Measurement> entry : mDnsUdpChecks.entrySet()) {
if (entry.getKey() instanceof Inet4Address) {
pw.println(entry.getValue().toString());
@@ -276,13 +305,15 @@ public class NetworkDiagnostics {
private class SimpleSocketCheck implements Closeable {
+ protected final InetAddress mSource; // Usually null.
protected final InetAddress mTarget;
protected final int mAddressFamily;
protected final Measurement mMeasurement;
protected FileDescriptor mFileDescriptor;
protected SocketAddress mSocketAddress;
- protected SimpleSocketCheck(InetAddress target, Measurement measurement) {
+ protected SimpleSocketCheck(
+ InetAddress source, InetAddress target, Measurement measurement) {
mMeasurement = measurement;
if (target instanceof Inet6Address) {
@@ -301,6 +332,14 @@ public class NetworkDiagnostics {
mTarget = target;
mAddressFamily = AF_INET;
}
+
+ // We don't need to check the scope ID here because we currently only do explicit-source
+ // measurements from global IPv6 addresses.
+ mSource = source;
+ }
+
+ protected SimpleSocketCheck(InetAddress target, Measurement measurement) {
+ this(null, target, measurement);
}
protected void setupSocket(
@@ -314,6 +353,9 @@ public class NetworkDiagnostics {
SOL_SOCKET, SO_RCVTIMEO, StructTimeval.fromMillis(readTimeout));
// TODO: Use IP_RECVERR/IPV6_RECVERR, pending OsContants availability.
mNetwork.bindSocket(mFileDescriptor);
+ if (mSource != null) {
+ Os.bind(mFileDescriptor, mSource, 0);
+ }
Os.connect(mFileDescriptor, mTarget, dstPort);
mSocketAddress = Os.getsockname(mFileDescriptor);
}
@@ -343,8 +385,8 @@ public class NetworkDiagnostics {
private final int mProtocol;
private final int mIcmpType;
- public IcmpCheck(InetAddress target, Measurement measurement) {
- super(target, measurement);
+ public IcmpCheck(InetAddress source, InetAddress target, Measurement measurement) {
+ super(source, target, measurement);
if (mAddressFamily == AF_INET6) {
mProtocol = IPPROTO_ICMPV6;
@@ -359,6 +401,10 @@ public class NetworkDiagnostics {
mMeasurement.description += " dst{" + mTarget.getHostAddress() + "}";
}
+ public IcmpCheck(InetAddress target, Measurement measurement) {
+ this(null, target, measurement);
+ }
+
@Override
public void run() {
// Check if this measurement has already failed during setup.
diff --git a/services/core/java/com/android/server/display/DisplayAdapter.java b/services/core/java/com/android/server/display/DisplayAdapter.java
index 6ba25a53248d..701b9f179f9c 100644
--- a/services/core/java/com/android/server/display/DisplayAdapter.java
+++ b/services/core/java/com/android/server/display/DisplayAdapter.java
@@ -49,6 +49,13 @@ abstract class DisplayAdapter {
*/
private static final AtomicInteger NEXT_DISPLAY_MODE_ID = new AtomicInteger(1); // 0 = no mode.
+ /**
+ * Used to generate globally unique color transform ids.
+ *
+ * Valid IDs start at 1 with 0 as the sentinel value for the default mode.
+ */
+ private static final AtomicInteger NEXT_COLOR_TRANSFORM_ID = new AtomicInteger(1);
+
// Called with SyncRoot lock held.
public DisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
Context context, Handler handler, Listener listener, String name) {
@@ -134,6 +141,11 @@ abstract class DisplayAdapter {
NEXT_DISPLAY_MODE_ID.getAndIncrement(), width, height, refreshRate);
}
+ public static Display.ColorTransform createColorTransform(int colorTransform) {
+ return new Display.ColorTransform(
+ NEXT_COLOR_TRANSFORM_ID.getAndIncrement(), colorTransform);
+ }
+
public interface Listener {
public void onDisplayDeviceEvent(DisplayDevice device, int event);
public void onTraversalRequested();
diff --git a/services/core/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java
index 93bda46873a1..7af0bdbdc357 100644
--- a/services/core/java/com/android/server/display/DisplayDevice.java
+++ b/services/core/java/com/android/server/display/DisplayDevice.java
@@ -135,7 +135,7 @@ abstract class DisplayDevice {
/**
* Sets the mode, if supported.
*/
- public void requestModeInTransactionLocked(int id) {
+ public void requestColorTransformAndModeInTransactionLocked(int colorTransformId, int modeId) {
}
/**
diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
index 97ada1542466..55ba3025c516 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
@@ -155,6 +155,15 @@ final class DisplayDeviceInfo {
*/
public Display.Mode[] supportedModes = Display.Mode.EMPTY_ARRAY;
+ /** The active color transform of the display */
+ public int colorTransformId;
+
+ /** The default color transform of the display */
+ public int defaultColorTransformId;
+
+ /** The supported color transforms of the display */
+ public Display.ColorTransform[] supportedColorTransforms = Display.ColorTransform.EMPTY_ARRAY;
+
/**
* The nominal apparent density of the display in DPI used for layout calculations.
* This density is sensitive to the viewing distance. A big TV and a tablet may have
@@ -276,6 +285,9 @@ final class DisplayDeviceInfo {
|| modeId != other.modeId
|| defaultModeId != other.defaultModeId
|| !Arrays.equals(supportedModes, other.supportedModes)
+ || colorTransformId != other.colorTransformId
+ || defaultColorTransformId != other.defaultColorTransformId
+ || !Arrays.equals(supportedColorTransforms, other.supportedColorTransforms)
|| densityDpi != other.densityDpi
|| xDpi != other.xDpi
|| yDpi != other.yDpi
@@ -306,6 +318,9 @@ final class DisplayDeviceInfo {
modeId = other.modeId;
defaultModeId = other.defaultModeId;
supportedModes = other.supportedModes;
+ colorTransformId = other.colorTransformId;
+ defaultColorTransformId = other.defaultColorTransformId;
+ supportedColorTransforms = other.supportedColorTransforms;
densityDpi = other.densityDpi;
xDpi = other.xDpi;
yDpi = other.yDpi;
@@ -331,6 +346,9 @@ final class DisplayDeviceInfo {
sb.append(", modeId ").append(modeId);
sb.append(", defaultModeId ").append(defaultModeId);
sb.append(", supportedModes ").append(Arrays.toString(supportedModes));
+ sb.append(", colorTransformId ").append(colorTransformId);
+ sb.append(", defaultColorTransformId ").append(defaultColorTransformId);
+ sb.append(", supportedColorTransforms ").append(Arrays.toString(supportedColorTransforms));
sb.append(", density ").append(densityDpi);
sb.append(", ").append(xDpi).append(" x ").append(yDpi).append(" dpi");
sb.append(", appVsyncOff ").append(appVsyncOffsetNanos);
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index b2ab797a409e..6a6570b97205 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -540,6 +540,17 @@ public final class DisplayManagerService extends SystemService {
}
}
+ private void requestColorTransformInternal(int displayId, int colorTransformId) {
+ synchronized (mSyncRoot) {
+ LogicalDisplay display = mLogicalDisplays.get(displayId);
+ if (display != null &&
+ display.getRequestedColorTransformIdLocked() != colorTransformId) {
+ display.setRequestedColorTransformIdLocked(colorTransformId);
+ scheduleTraversalLocked(false);
+ }
+ }
+ }
+
private int createVirtualDisplayInternal(IVirtualDisplayCallback callback,
IMediaProjection projection, int callingUid, String packageName,
String name, int width, int height, int densityDpi, Surface surface, int flags) {
@@ -1340,6 +1351,19 @@ public final class DisplayManagerService extends SystemService {
}
@Override // Binder call
+ public void requestColorTransform(int displayId, int colorTransformId) {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.CONFIGURE_DISPLAY_COLOR_TRANSFORM,
+ "Permission required to change the display color transform");
+ final long token = Binder.clearCallingIdentity();
+ try {
+ requestColorTransformInternal(displayId, colorTransformId);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override // Binder call
public int createVirtualDisplay(IVirtualDisplayCallback callback,
IMediaProjection projection, String packageName, String name,
int width, int height, int densityDpi, Surface surface, int flags) {
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 517a825f6fcb..088d96e4a6e0 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -31,6 +31,7 @@ import android.os.SystemProperties;
import android.os.Trace;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.SparseBooleanArray;
import android.view.Display;
import android.view.DisplayEventReceiver;
import android.view.Surface;
@@ -38,6 +39,7 @@ import android.view.SurfaceControl;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Arrays;
/**
* A display adapter for the local displays managed by Surface Flinger.
@@ -143,14 +145,22 @@ final class LocalDisplayAdapter extends DisplayAdapter {
private final int mBuiltInDisplayId;
private final Light mBacklight;
private final SparseArray<DisplayModeRecord> mSupportedModes = new SparseArray<>();
+ private final SparseArray<Display.ColorTransform> mSupportedColorTransforms =
+ new SparseArray<>();
private DisplayDeviceInfo mInfo;
private boolean mHavePendingChanges;
private int mState = Display.STATE_UNKNOWN;
private int mBrightness = PowerManager.BRIGHTNESS_DEFAULT;
+ private int mActivePhysIndex;
private int mDefaultModeId;
private int mActiveModeId;
private boolean mActiveModeInvalid;
+ private int mDefaultColorTransformId;
+ private int mActiveColorTransformId;
+ private boolean mActiveColorTransformInvalid;
+
+ private SurfaceControl.PhysicalDisplayInfo mDisplayInfos[];
public LocalDisplayDevice(IBinder displayToken, int builtInDisplayId,
SurfaceControl.PhysicalDisplayInfo[] physicalDisplayInfos, int activeDisplayInfo) {
@@ -167,22 +177,73 @@ final class LocalDisplayAdapter extends DisplayAdapter {
public boolean updatePhysicalDisplayInfoLocked(
SurfaceControl.PhysicalDisplayInfo[] physicalDisplayInfos, int activeDisplayInfo) {
+ mDisplayInfos = Arrays.copyOf(physicalDisplayInfos, physicalDisplayInfos.length);
+ mActivePhysIndex = activeDisplayInfo;
+ ArrayList<Display.ColorTransform> colorTransforms = new ArrayList<>();
+
+ // Build an updated list of all existing color transforms.
+ boolean colorTransformsAdded = false;
+ Display.ColorTransform activeColorTransform = null;
+ for (int i = 0; i < physicalDisplayInfos.length; i++) {
+ SurfaceControl.PhysicalDisplayInfo info = physicalDisplayInfos[i];
+ // First check to see if we've already added this color transform
+ boolean existingMode = false;
+ for (int j = 0; j < colorTransforms.size(); j++) {
+ if (colorTransforms.get(j).getColorTransform() == info.colorTransform) {
+ existingMode = true;
+ break;
+ }
+ }
+ if (existingMode) {
+ continue;
+ }
+ Display.ColorTransform colorTransform = findColorTransform(info);
+ if (colorTransform == null) {
+ colorTransform = createColorTransform(info.colorTransform);
+ colorTransformsAdded = true;
+ }
+ colorTransforms.add(colorTransform);
+ if (i == activeDisplayInfo) {
+ activeColorTransform = colorTransform;
+ }
+ }
+
// Build an updated list of all existing modes.
- boolean modesAdded = false;
- DisplayModeRecord activeRecord = null;
ArrayList<DisplayModeRecord> records = new ArrayList<DisplayModeRecord>();
+ boolean modesAdded = false;
for (int i = 0; i < physicalDisplayInfos.length; i++) {
SurfaceControl.PhysicalDisplayInfo info = physicalDisplayInfos[i];
+ // First, check to see if we've already added a matching mode. Since not all
+ // configuration options are exposed via Display.Mode, it's possible that we have
+ // multiple PhysicalDisplayInfos that would generate the same Display.Mode.
+ boolean existingMode = false;
+ for (int j = 0; j < records.size(); j++) {
+ if (records.get(j).hasMatchingMode(info)) {
+ existingMode = true;
+ break;
+ }
+ }
+ if (existingMode) {
+ continue;
+ }
+ // If we haven't already added a mode for this configuration to the new set of
+ // supported modes then check to see if we have one in the prior set of supported
+ // modes to reuse.
DisplayModeRecord record = findDisplayModeRecord(info);
- if (record != null) {
- record.mPhysIndex = i;
- } else {
- record = new DisplayModeRecord(info, i);
+ if (record == null) {
+ record = new DisplayModeRecord(info);
modesAdded = true;
}
records.add(record);
- if (i == activeDisplayInfo) {
+ }
+
+ // Get the currently active mode
+ DisplayModeRecord activeRecord = null;
+ for (int i = 0; i < records.size(); i++) {
+ DisplayModeRecord record = records.get(i);
+ if (record.hasMatchingMode(physicalDisplayInfos[activeDisplayInfo])){
activeRecord = record;
+ break;
}
}
// Check whether surface flinger spontaneously changed modes out from under us. Schedule
@@ -192,25 +253,48 @@ final class LocalDisplayAdapter extends DisplayAdapter {
mActiveModeInvalid = true;
sendTraversalRequestLocked();
}
- // If no modes were added and we have the same number of modes as before, then nothing
- // actually changed except possibly the physical index (which we only care about when
- // setting the mode) so we're done.
- if (records.size() == mSupportedModes.size() && !modesAdded) {
+ // Check whether surface flinger spontaneously changed color transforms out from under
+ // us.
+ if (mActiveColorTransformId != 0
+ && mActiveColorTransformId != activeColorTransform.getId()) {
+ mActiveColorTransformInvalid = true;
+ sendTraversalRequestLocked();
+ }
+
+ boolean colorTransformsChanged =
+ colorTransforms.size() != mSupportedColorTransforms.size()
+ || colorTransformsAdded;
+ boolean recordsChanged = records.size() != mSupportedModes.size() || modesAdded;
+ // If neither the records nor the supported color transforms have changed then we're
+ // done here.
+ if (!recordsChanged && !colorTransformsChanged) {
return false;
}
// Update the index of modes.
mHavePendingChanges = true;
+
mSupportedModes.clear();
for (DisplayModeRecord record : records) {
mSupportedModes.put(record.mMode.getModeId(), record);
}
- // Update the default mode if needed.
- if (mSupportedModes.indexOfKey(mDefaultModeId) < 0) {
+ mSupportedColorTransforms.clear();
+ for (Display.ColorTransform colorTransform : colorTransforms) {
+ mSupportedColorTransforms.put(colorTransform.getId(), colorTransform);
+ }
+
+ // Update the default mode and color transform if needed. This needs to be done in
+ // tandem so we always have a default state to fall back to.
+ if (findDisplayInfoIndexLocked(mDefaultColorTransformId, mDefaultModeId) < 0) {
if (mDefaultModeId != 0) {
- Slog.w(TAG, "Default display mode no longer available, using currently active"
- + " mode as default.");
+ Slog.w(TAG, "Default display mode no longer available, using currently"
+ + " active mode as default.");
}
mDefaultModeId = activeRecord.mMode.getModeId();
+ if (mDefaultColorTransformId != 0) {
+ Slog.w(TAG, "Default color transform no longer available, using currently"
+ + " active color transform as default");
+ }
+ mDefaultColorTransformId = activeColorTransform.getId();
}
// Determine whether the active mode is still there.
if (mSupportedModes.indexOfKey(mActiveModeId) < 0) {
@@ -221,6 +305,16 @@ final class LocalDisplayAdapter extends DisplayAdapter {
mActiveModeId = mDefaultModeId;
mActiveModeInvalid = true;
}
+
+ // Determine whether the active color transform is still there.
+ if (mSupportedColorTransforms.indexOfKey(mActiveColorTransformId) < 0) {
+ if (mActiveColorTransformId != 0) {
+ Slog.w(TAG, "Active color transform no longer available, reverting"
+ + " to default transform.");
+ }
+ mActiveColorTransformId = mDefaultColorTransformId;
+ mActiveColorTransformInvalid = true;
+ }
// Schedule traversals so that we apply pending changes.
sendTraversalRequestLocked();
return true;
@@ -229,13 +323,23 @@ final class LocalDisplayAdapter extends DisplayAdapter {
private DisplayModeRecord findDisplayModeRecord(SurfaceControl.PhysicalDisplayInfo info) {
for (int i = 0; i < mSupportedModes.size(); i++) {
DisplayModeRecord record = mSupportedModes.valueAt(i);
- if (record.mPhys.equals(info)) {
+ if (record.hasMatchingMode(info)) {
return record;
}
}
return null;
}
+ private Display.ColorTransform findColorTransform(SurfaceControl.PhysicalDisplayInfo info) {
+ for (int i = 0; i < mSupportedColorTransforms.size(); i++) {
+ Display.ColorTransform transform = mSupportedColorTransforms.valueAt(i);
+ if (transform.getColorTransform() == info.colorTransform) {
+ return transform;
+ }
+ }
+ return null;
+ }
+
@Override
public void applyPendingDisplayDeviceInfoChangesLocked() {
if (mHavePendingChanges) {
@@ -247,7 +351,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
@Override
public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
if (mInfo == null) {
- SurfaceControl.PhysicalDisplayInfo phys = mSupportedModes.get(mActiveModeId).mPhys;
+ SurfaceControl.PhysicalDisplayInfo phys = mDisplayInfos[mActivePhysIndex];
mInfo = new DisplayDeviceInfo();
mInfo.width = phys.width;
mInfo.height = phys.height;
@@ -258,6 +362,13 @@ final class LocalDisplayAdapter extends DisplayAdapter {
DisplayModeRecord record = mSupportedModes.valueAt(i);
mInfo.supportedModes[i] = record.mMode;
}
+ mInfo.colorTransformId = mActiveColorTransformId;
+ mInfo.defaultColorTransformId = mDefaultColorTransformId;
+ mInfo.supportedColorTransforms =
+ new Display.ColorTransform[mSupportedColorTransforms.size()];
+ for (int i = 0; i < mSupportedColorTransforms.size(); i++) {
+ mInfo.supportedColorTransforms[i] = mSupportedColorTransforms.valueAt(i);
+ }
mInfo.appVsyncOffsetNanos = phys.appVsyncOffsetNanos;
mInfo.presentationDeadlineNanos = phys.presentationDeadlineNanos;
mInfo.state = mState;
@@ -402,7 +513,8 @@ final class LocalDisplayAdapter extends DisplayAdapter {
}
@Override
- public void requestModeInTransactionLocked(int modeId) {
+ public void requestColorTransformAndModeInTransactionLocked(
+ int colorTransformId, int modeId) {
if (modeId == 0) {
modeId = mDefaultModeId;
} else if (mSupportedModes.indexOfKey(modeId) < 0) {
@@ -410,13 +522,37 @@ final class LocalDisplayAdapter extends DisplayAdapter {
+ " reverting to default display mode.");
modeId = mDefaultModeId;
}
- if (mActiveModeId == modeId && !mActiveModeInvalid) {
+
+ if (colorTransformId == 0) {
+ colorTransformId = mDefaultColorTransformId;
+ } else if (mSupportedColorTransforms.indexOfKey(colorTransformId) < 0) {
+ Slog.w(TAG, "Requested color transform " + colorTransformId + " is not supported"
+ + " by this display, reverting to the default color transform");
+ colorTransformId = mDefaultColorTransformId;
+ }
+ int physIndex = findDisplayInfoIndexLocked(colorTransformId, modeId);
+ if (physIndex < 0) {
+ Slog.w(TAG, "Requested color transform, mode ID pair (" + colorTransformId + ", "
+ + modeId + ") not available, trying color transform with default mode ID");
+ modeId = mDefaultModeId;
+ physIndex = findDisplayInfoIndexLocked(colorTransformId, modeId);
+ if (physIndex < 0) {
+ Slog.w(TAG, "Requested color transform with default mode ID still not"
+ + " available, falling back to default color transform with default"
+ + " mode.");
+ colorTransformId = mDefaultColorTransformId;
+ physIndex = findDisplayInfoIndexLocked(colorTransformId, modeId);
+ }
+ }
+ if (mActivePhysIndex == physIndex) {
return;
}
- DisplayModeRecord record = mSupportedModes.get(modeId);
- SurfaceControl.setActiveConfig(getDisplayTokenLocked(), record.mPhysIndex);
+ SurfaceControl.setActiveConfig(getDisplayTokenLocked(), physIndex);
+ mActivePhysIndex = physIndex;
mActiveModeId = modeId;
mActiveModeInvalid = false;
+ mActiveColorTransformId = colorTransformId;
+ mActiveColorTransformInvalid = false;
updateDeviceInfoLocked();
}
@@ -424,10 +560,43 @@ final class LocalDisplayAdapter extends DisplayAdapter {
public void dumpLocked(PrintWriter pw) {
super.dumpLocked(pw);
pw.println("mBuiltInDisplayId=" + mBuiltInDisplayId);
+ pw.println("mActivePhysIndex=" + mActivePhysIndex);
pw.println("mActiveModeId=" + mActiveModeId);
+ pw.println("mActiveColorTransformId=" + mActiveColorTransformId);
pw.println("mState=" + Display.stateToString(mState));
pw.println("mBrightness=" + mBrightness);
pw.println("mBacklight=" + mBacklight);
+ pw.println("mDisplayInfos=");
+ for (int i = 0; i < mDisplayInfos.length; i++) {
+ pw.println(" " + mDisplayInfos[i]);
+ }
+ pw.println("mSupportedModes=");
+ for (int i = 0; i < mSupportedModes.size(); i++) {
+ pw.println(" " + mSupportedModes.valueAt(i));
+ }
+ pw.println("mSupportedColorTransforms=[");
+ for (int i = 0; i < mSupportedColorTransforms.size(); i++) {
+ if (i != 0) {
+ pw.print(", ");
+ }
+ pw.print(mSupportedColorTransforms.valueAt(i));
+ }
+ pw.println("]");
+ }
+
+ private int findDisplayInfoIndexLocked(int colorTransformId, int modeId) {
+ DisplayModeRecord record = mSupportedModes.get(modeId);
+ Display.ColorTransform transform = mSupportedColorTransforms.get(colorTransformId);
+ if (record != null && transform != null) {
+ for (int i = 0; i < mDisplayInfos.length; i++) {
+ SurfaceControl.PhysicalDisplayInfo info = mDisplayInfos[i];
+ if (info.colorTransform == transform.getColorTransform()
+ && record.hasMatchingMode(info)){
+ return i;
+ }
+ }
+ }
+ return -1;
}
private void updateDeviceInfoLocked() {
@@ -441,13 +610,28 @@ final class LocalDisplayAdapter extends DisplayAdapter {
*/
private static final class DisplayModeRecord {
public final Display.Mode mMode;
- public final SurfaceControl.PhysicalDisplayInfo mPhys;
- public int mPhysIndex;
- public DisplayModeRecord(SurfaceControl.PhysicalDisplayInfo phys, int physIndex) {
+ public DisplayModeRecord(SurfaceControl.PhysicalDisplayInfo phys) {
mMode = createMode(phys.width, phys.height, phys.refreshRate);
- mPhys = phys;
- mPhysIndex = physIndex;
+ }
+
+ /**
+ * Returns whether the mode generated by the given PhysicalDisplayInfo matches the mode
+ * contained by the record modulo mode ID.
+ *
+ * Note that this doesn't necessarily mean the the PhysicalDisplayInfos are identical, just
+ * that they generate identical modes.
+ */
+ public boolean hasMatchingMode(SurfaceControl.PhysicalDisplayInfo info) {
+ int modeRefreshRate = Float.floatToIntBits(mMode.getRefreshRate());
+ int displayInfoRefreshRate = Float.floatToIntBits(info.refreshRate);
+ return mMode.getPhysicalWidth() == info.width
+ && mMode.getPhysicalHeight() == info.height
+ && modeRefreshRate == displayInfoRefreshRate;
+ }
+
+ public String toString() {
+ return "DisplayModeRecord{mMode=" + mMode + "}";
}
}
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index 6efc99a0c342..6dae397cff21 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -74,6 +74,7 @@ final class LogicalDisplay {
private boolean mHasContent;
private int mRequestedModeId;
+ private int mRequestedColorTransformId;
// The display offsets to apply to the display projection.
private int mDisplayOffsetX;
@@ -235,6 +236,11 @@ final class LogicalDisplay {
mBaseDisplayInfo.defaultModeId = deviceInfo.defaultModeId;
mBaseDisplayInfo.supportedModes = Arrays.copyOf(
deviceInfo.supportedModes, deviceInfo.supportedModes.length);
+ mBaseDisplayInfo.colorTransformId = deviceInfo.colorTransformId;
+ mBaseDisplayInfo.defaultColorTransformId = deviceInfo.defaultColorTransformId;
+ mBaseDisplayInfo.supportedColorTransforms = Arrays.copyOf(
+ deviceInfo.supportedColorTransforms,
+ deviceInfo.supportedColorTransforms.length);
mBaseDisplayInfo.logicalDensityDpi = deviceInfo.densityDpi;
mBaseDisplayInfo.physicalXDpi = deviceInfo.xDpi;
mBaseDisplayInfo.physicalYDpi = deviceInfo.yDpi;
@@ -275,11 +281,12 @@ final class LogicalDisplay {
// Set the layer stack.
device.setLayerStackInTransactionLocked(isBlanked ? BLANK_LAYER_STACK : mLayerStack);
- // Set the mode.
+ // Set the color transform and mode.
if (device == mPrimaryDisplayDevice) {
- device.requestModeInTransactionLocked(mRequestedModeId);
+ device.requestColorTransformAndModeInTransactionLocked(
+ mRequestedColorTransformId, mRequestedModeId);
} else {
- device.requestModeInTransactionLocked(0); // Revert to default.
+ device.requestColorTransformAndModeInTransactionLocked(0, 0); // Revert to default.
}
// Only grab the display info now as it may have been changed based on the requests above.
@@ -383,6 +390,18 @@ final class LogicalDisplay {
}
/**
+ * Requests the given color transform.
+ */
+ public void setRequestedColorTransformIdLocked(int colorTransformId) {
+ mRequestedColorTransformId = colorTransformId;
+ }
+
+ /** Returns the pending requested color transform. */
+ public int getRequestedColorTransformIdLocked() {
+ return mRequestedColorTransformId;
+ }
+
+ /**
* Gets the burn-in offset in X.
*/
public int getDisplayOffsetXLocked() {
@@ -409,6 +428,7 @@ final class LogicalDisplay {
pw.println("mLayerStack=" + mLayerStack);
pw.println("mHasContent=" + mHasContent);
pw.println("mRequestedMode=" + mRequestedModeId);
+ pw.println("mRequestedColorTransformId=" + mRequestedColorTransformId);
pw.println("mDisplayOffset=(" + mDisplayOffsetX + ", " + mDisplayOffsetY + ")");
pw.println("mPrimaryDisplayDevice=" + (mPrimaryDisplayDevice != null ?
mPrimaryDisplayDevice.getNameLocked() : "null"));
diff --git a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
index 0bddff076c18..cf6264ace34f 100644
--- a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
@@ -310,7 +310,7 @@ final class OverlayDisplayAdapter extends DisplayAdapter {
}
@Override
- public void requestModeInTransactionLocked(int id) {
+ public void requestColorTransformAndModeInTransactionLocked(int color, int id) {
int index = -1;
if (id == 0) {
// Use the default.
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index ea7d85e36944..ec7c1c437d92 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -337,7 +337,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
return;
}
stopPendingOperations(true);
- mEnrollClient = new ClientMonitor(token, receiver, groupId, restricted);
+ mEnrollClient = new ClientMonitor(token, receiver, groupId, restricted, token.toString());
final int timeout = (int) (ENROLLMENT_TIMEOUT_MS / MS_PER_SEC);
try {
final int result = daemon.enroll(cryptoToken, groupId, timeout);
@@ -417,14 +417,15 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
}
void startAuthentication(IBinder token, long opId, int groupId,
- IFingerprintServiceReceiver receiver, int flags, boolean restricted) {
+ IFingerprintServiceReceiver receiver, int flags, boolean restricted,
+ String opPackageName) {
IFingerprintDaemon daemon = getFingerprintDaemon();
if (daemon == null) {
Slog.w(TAG, "startAuthentication: no fingeprintd!");
return;
}
stopPendingOperations(true);
- mAuthClient = new ClientMonitor(token, receiver, groupId, restricted);
+ mAuthClient = new ClientMonitor(token, receiver, groupId, restricted, opPackageName);
if (inLockoutMode()) {
Slog.v(TAG, "In lockout mode; disallowing authentication");
if (!mAuthClient.sendError(FingerprintManager.FINGERPRINT_ERROR_LOCKOUT)) {
@@ -481,7 +482,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
}
stopPendingOperations(true);
- mRemoveClient = new ClientMonitor(token, receiver, userId, restricted);
+ mRemoveClient = new ClientMonitor(token, receiver, userId, restricted, token.toString());
// The fingerprint template ids will be removed when we get confirmation from the HAL
try {
final int result = daemon.remove(fingerId, userId);
@@ -574,11 +575,11 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
}
if (mAppOps.noteOp(AppOpsManager.OP_USE_FINGERPRINT, uid, opPackageName)
!= AppOpsManager.MODE_ALLOWED) {
- Slog.v(TAG, "Rejecting " + opPackageName + " ; permission denied");
+ Slog.w(TAG, "Rejecting " + opPackageName + " ; permission denied");
return false;
}
if (foregroundOnly && !isForegroundActivity(uid, pid)) {
- Slog.v(TAG, "Rejecting " + opPackageName + " ; not in foreground");
+ Slog.w(TAG, "Rejecting " + opPackageName + " ; not in foreground");
return false;
}
return true;
@@ -606,13 +607,15 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
IFingerprintServiceReceiver receiver;
int userId;
boolean restricted; // True if client does not have MANAGE_FINGERPRINT permission
+ String owner;
public ClientMonitor(IBinder token, IFingerprintServiceReceiver receiver, int userId,
- boolean restricted) {
+ boolean restricted, String owner) {
this.token = token;
this.receiver = receiver;
this.userId = userId;
this.restricted = restricted;
+ this.owner = owner; // name of the client that owns this - for debugging
try {
token.linkToDeath(this, 0);
} catch (RemoteException e) {
@@ -695,6 +698,10 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
if (!authenticated) {
receiver.onAuthenticationFailed(mHalDeviceId);
} else {
+ if (DEBUG) {
+ Slog.v(TAG, "onAuthenticated(owner=" + mAuthClient.owner
+ + ", id=" + fpId + ", gp=" + groupId + ")");
+ }
Fingerprint fp = !restricted ?
new Fingerprint("" /* TODO */, groupId, fpId, mHalDeviceId) : null;
receiver.onAuthenticationSucceeded(mHalDeviceId, fp);
@@ -915,6 +922,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
final IFingerprintServiceReceiver receiver, final int flags,
final String opPackageName) {
if (!canUseFingerprint(opPackageName, true /* foregroundOnly */)) {
+ if (DEBUG) Slog.v(TAG, "authenticate(): reject " + opPackageName);
return;
}
@@ -927,7 +935,8 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
@Override
public void run() {
MetricsLogger.histogram(mContext, "fingerprint_token", opId != 0L ? 1 : 0);
- startAuthentication(token, opId, effectiveGroupId, receiver, flags, restricted);
+ startAuthentication(token, opId, effectiveGroupId, receiver, flags, restricted,
+ opPackageName);
}
});
}
diff --git a/services/core/java/com/android/server/firewall/SenderPackageFilter.java b/services/core/java/com/android/server/firewall/SenderPackageFilter.java
index ec9b5ded511e..dc3edd9c7888 100644
--- a/services/core/java/com/android/server/firewall/SenderPackageFilter.java
+++ b/services/core/java/com/android/server/firewall/SenderPackageFilter.java
@@ -44,7 +44,9 @@ public class SenderPackageFilter implements Filter {
int packageUid = -1;
try {
- packageUid = pm.getPackageUid(mPackageName, UserHandle.USER_OWNER);
+ // USER_SYSTEM here is not important. Only app id is used and getPackageUid() will
+ // return a uid whether the app is installed for a user or not.
+ packageUid = pm.getPackageUid(mPackageName, UserHandle.USER_SYSTEM);
} catch (RemoteException ex) {
// handled below
}
diff --git a/services/core/java/com/android/server/location/GeofenceProxy.java b/services/core/java/com/android/server/location/GeofenceProxy.java
index d1bb8db221f4..b3a001022556 100644
--- a/services/core/java/com/android/server/location/GeofenceProxy.java
+++ b/services/core/java/com/android/server/location/GeofenceProxy.java
@@ -94,7 +94,7 @@ public final class GeofenceProxy {
private void bindHardwareGeofence() {
mContext.bindServiceAsUser(new Intent(mContext, GeofenceHardwareService.class),
- mServiceConnection, Context.BIND_AUTO_CREATE, UserHandle.OWNER);
+ mServiceConnection, Context.BIND_AUTO_CREATE, UserHandle.SYSTEM);
}
private ServiceConnection mServiceConnection = new ServiceConnection() {
diff --git a/services/core/java/com/android/server/location/GpsLocationProvider.java b/services/core/java/com/android/server/location/GpsLocationProvider.java
index 5e5a55cc2249..bc9f5205e1c5 100644
--- a/services/core/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/core/java/com/android/server/location/GpsLocationProvider.java
@@ -22,8 +22,6 @@ import com.android.internal.location.GpsNetInitiatedHandler;
import com.android.internal.location.GpsNetInitiatedHandler.GpsNiNotification;
import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
-import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.PhoneConstants;
import android.app.AlarmManager;
import android.app.AppOpsManager;
@@ -50,7 +48,10 @@ import android.location.LocationManager;
import android.location.LocationProvider;
import android.location.LocationRequest;
import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
+import android.net.NetworkRequest;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.BatteryStats;
@@ -199,6 +200,8 @@ public class GpsLocationProvider implements LocationProviderInterface {
private static final int DOWNLOAD_XTRA_DATA_FINISHED = 11;
private static final int SUBSCRIPTION_OR_SIM_CHANGED = 12;
private static final int INITIALIZE_HANDLER = 13;
+ private static final int REQUEST_SUPL_CONNECTION = 14;
+ private static final int RELEASE_SUPL_CONNECTION = 15;
// Request setid
private static final int AGPS_RIL_REQUEST_SETID_IMSI = 1;
@@ -295,9 +298,6 @@ public class GpsLocationProvider implements LocationProviderInterface {
// true if we are enabled, protected by this
private boolean mEnabled;
- // true if we have network connectivity
- private boolean mNetworkAvailable;
-
// states for injecting ntp and downloading xtra data
private static final int STATE_PENDING_NETWORK = 0;
private static final int STATE_DOWNLOADING = 1;
@@ -372,10 +372,11 @@ public class GpsLocationProvider implements LocationProviderInterface {
// Handler for processing events
private Handler mHandler;
- private String mAGpsApn;
- private int mApnIpType;
+ /** It must be accessed only inside {@link #mHandler}. */
private int mAGpsDataConnectionState;
+ /** It must be accessed only inside {@link #mHandler}. */
private InetAddress mAGpsDataConnectionIpAddr;
+
private final ConnectivityManager mConnMgr;
private final GpsNetInitiatedHandler mNIHandler;
@@ -431,6 +432,42 @@ public class GpsLocationProvider implements LocationProviderInterface {
return mGpsNavigationMessageProvider;
}
+ /**
+ * Callback used to listen for data connectivity changes.
+ */
+ private final ConnectivityManager.NetworkCallback mNetworkConnectivityCallback =
+ new ConnectivityManager.NetworkCallback() {
+ @Override
+ public void onAvailable(Network network) {
+ requestUtcTime();
+ xtraDownloadRequest();
+ }
+ };
+
+ /**
+ * Callback used to listen for availability of a requested SUPL connection.
+ * It is kept as a separate instance from {@link #mNetworkConnectivityCallback} to be able to
+ * manage the registration/un-registration lifetimes separate.
+ */
+ private final ConnectivityManager.NetworkCallback mSuplConnectivityCallback =
+ new ConnectivityManager.NetworkCallback() {
+ @Override
+ public void onAvailable(Network network) {
+ sendMessage(UPDATE_NETWORK_STATE, 0 /*arg*/, network);
+ }
+
+ @Override
+ public void onLost(Network network) {
+ releaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN);
+ }
+
+ @Override
+ public void onUnavailable() {
+ // timeout, it was not possible to establish the required connection
+ releaseSuplConnection(GPS_AGPS_DATA_CONN_FAILED);
+ }
+ };
+
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
@@ -447,16 +484,6 @@ public class GpsLocationProvider implements LocationProviderInterface {
checkSmsSuplInit(intent);
} else if (action.equals(Intents.WAP_PUSH_RECEIVED_ACTION)) {
checkWapSuplInit(intent);
- } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)
- || action.equals(ConnectivityManager.CONNECTIVITY_ACTION_SUPL)) {
- // retrieve NetworkType result for this UID
- int networkType = intent.getIntExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, -1);
- if (DEBUG) Log.d(TAG, "Connectivity action, type=" + networkType);
- if (networkType == ConnectivityManager.TYPE_MOBILE
- || networkType == ConnectivityManager.TYPE_WIFI
- || networkType == ConnectivityManager.TYPE_MOBILE_SUPL) {
- updateNetworkState(networkType);
- }
} else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action)
|| PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action)
|| Intent.ACTION_SCREEN_OFF.equals(action)
@@ -574,7 +601,7 @@ public class GpsLocationProvider implements LocationProviderInterface {
native_configuration_update(baos.toString());
Log.d(TAG, "final config = " + baos.toString());
} catch (IOException ex) {
- Log.w(TAG, "failed to dump properties contents");
+ Log.e(TAG, "failed to dump properties contents");
}
} else if (DEBUG) {
Log.d(TAG, "Skipped configuration update because GNSS configuration in GPS HAL is not"
@@ -740,78 +767,117 @@ public class GpsLocationProvider implements LocationProviderInterface {
return PROPERTIES;
}
- public void updateNetworkState(int networkType) {
- sendMessage(UPDATE_NETWORK_STATE, networkType, null /*obj*/);
- }
-
- private void handleUpdateNetworkState(int networkType) {
- ConnectivityManager connectivityManager = (ConnectivityManager) mContext
- .getSystemService(Context.CONNECTIVITY_SERVICE);
- NetworkInfo mobileInfo =
- connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
- NetworkInfo wifiInfo = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
- mNetworkAvailable = (mobileInfo != null && mobileInfo.isConnected())
- || (wifiInfo != null && wifiInfo.isConnected());
- NetworkInfo info = connectivityManager.getNetworkInfo(networkType);
- if (DEBUG) {
- Log.d(TAG, "updateNetworkState " + (mNetworkAvailable ? "available" : "unavailable")
- + " info: " + info);
+ private void handleUpdateNetworkState(Network network) {
+ // retrieve NetworkInfo for this UID
+ NetworkInfo info = mConnMgr.getNetworkInfo(network);
+ if (info == null) {
+ return;
}
- if (info != null) {
- if (native_is_agps_ril_supported()) {
- boolean dataEnabled = TelephonyManager.getDefault().getDataEnabled();
- boolean networkAvailable = info.isAvailable() && dataEnabled;
- String defaultApn = getSelectedApn();
- if (defaultApn == null) {
- defaultApn = "dummy-apn";
- }
-
- native_update_network_state(info.isConnected(), info.getType(),
- info.isRoaming(), networkAvailable,
- info.getExtraInfo(), defaultApn);
- } else if (DEBUG) {
- Log.d(TAG, "Skipped network state update because AGPS-RIL in GPS HAL is not"
- + " supported");
+ boolean isConnected = info.isConnected();
+ if (DEBUG) {
+ String message = String.format(
+ "UpdateNetworkState, state=%s, connected=%s, info=%s, capabilities=%S",
+ agpsDataConnStateAsString(),
+ isConnected,
+ info,
+ mConnMgr.getNetworkCapabilities(network));
+ Log.d(TAG, message);
+ }
+
+ if (native_is_agps_ril_supported()) {
+ boolean dataEnabled = TelephonyManager.getDefault().getDataEnabled();
+ boolean networkAvailable = info.isAvailable() && dataEnabled;
+ String defaultApn = getSelectedApn();
+ if (defaultApn == null) {
+ defaultApn = "dummy-apn";
}
+
+ native_update_network_state(
+ isConnected,
+ info.getType(),
+ info.isRoaming(),
+ networkAvailable,
+ info.getExtraInfo(),
+ defaultApn);
+ } else if (DEBUG) {
+ Log.d(TAG, "Skipped network state update because GPS HAL AGPS-RIL is not supported");
}
- if (info != null && info.getType() == ConnectivityManager.TYPE_MOBILE_SUPL
- && mAGpsDataConnectionState == AGPS_DATA_CONNECTION_OPENING) {
- if (info.isConnected()) {
+ if (mAGpsDataConnectionState == AGPS_DATA_CONNECTION_OPENING) {
+ if (isConnected) {
String apnName = info.getExtraInfo();
if (apnName == null) {
- /* Assign a dummy value in the case of C2K as otherwise we will have a runtime
- exception in the following call to native_agps_data_conn_open*/
+ // assign a dummy value in the case of C2K as otherwise we will have a runtime
+ // exception in the following call to native_agps_data_conn_open
apnName = "dummy-apn";
}
- mAGpsApn = apnName;
- mApnIpType = getApnIpType(apnName);
+ int apnIpType = getApnIpType(apnName);
setRouting();
if (DEBUG) {
String message = String.format(
"native_agps_data_conn_open: mAgpsApn=%s, mApnIpType=%s",
- mAGpsApn, mApnIpType);
+ apnName,
+ apnIpType);
Log.d(TAG, message);
}
- native_agps_data_conn_open(mAGpsApn, mApnIpType);
+ native_agps_data_conn_open(apnName, apnIpType);
mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN;
} else {
- Log.e(TAG, "call native_agps_data_conn_failed, info: " + info);
- mAGpsApn = null;
- mApnIpType = APN_INVALID;
- mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
- native_agps_data_conn_failed();
+ handleReleaseSuplConnection(GPS_AGPS_DATA_CONN_FAILED);
}
}
+ }
- if (mNetworkAvailable) {
- if (mInjectNtpTimePending == STATE_PENDING_NETWORK) {
- sendMessage(INJECT_NTP_TIME, 0, null);
- }
- if (mDownloadXtraDataPending == STATE_PENDING_NETWORK) {
- sendMessage(DOWNLOAD_XTRA_DATA, 0, null);
- }
+ private void handleRequestSuplConnection(InetAddress address) {
+ if (DEBUG) {
+ String message = String.format(
+ "requestSuplConnection, state=%s, address=%s",
+ agpsDataConnStateAsString(),
+ address);
+ Log.d(TAG, message);
+ }
+
+ if (mAGpsDataConnectionState != AGPS_DATA_CONNECTION_CLOSED) {
+ return;
+ }
+ mAGpsDataConnectionIpAddr = address;
+ mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING;
+
+ NetworkRequest.Builder requestBuilder = new NetworkRequest.Builder();
+ requestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
+ requestBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL);
+ NetworkRequest request = requestBuilder.build();
+ mConnMgr.requestNetwork(
+ request,
+ mSuplConnectivityCallback,
+ ConnectivityManager.MAX_NETWORK_REQUEST_TIMEOUT_MS);
+ }
+
+ private void handleReleaseSuplConnection(int agpsDataConnStatus) {
+ if (DEBUG) {
+ String message = String.format(
+ "releaseSuplConnection, state=%s, status=%s",
+ agpsDataConnStateAsString(),
+ agpsDataConnStatusAsString(agpsDataConnStatus));
+ Log.d(TAG, message);
+ }
+
+ if (mAGpsDataConnectionState == AGPS_DATA_CONNECTION_CLOSED) {
+ return;
+ }
+ mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
+
+ mConnMgr.unregisterNetworkCallback(mSuplConnectivityCallback);
+ switch (agpsDataConnStatus) {
+ case GPS_AGPS_DATA_CONN_FAILED:
+ native_agps_data_conn_failed();
+ break;
+ case GPS_RELEASE_AGPS_DATA_CONN:
+ native_agps_data_conn_closed();
+ break;
+ default:
+ Log.e(TAG, "Invalid status to release SUPL connection: " + agpsDataConnStatus);
}
}
@@ -820,7 +886,7 @@ public class GpsLocationProvider implements LocationProviderInterface {
// already downloading data
return;
}
- if (!mNetworkAvailable) {
+ if (!isDataNetworkConnected()) {
// try again when network is up
mInjectNtpTimePending = STATE_PENDING_NETWORK;
return;
@@ -888,7 +954,7 @@ public class GpsLocationProvider implements LocationProviderInterface {
// already downloading data
return;
}
- if (!mNetworkAvailable) {
+ if (!isDataNetworkConnected()) {
// try again when network is up
mDownloadXtraDataPending = STATE_PENDING_NETWORK;
return;
@@ -903,9 +969,7 @@ public class GpsLocationProvider implements LocationProviderInterface {
GpsXtraDownloader xtraDownloader = new GpsXtraDownloader(mProperties);
byte[] data = xtraDownloader.downloadXtraData();
if (data != null) {
- if (DEBUG) {
- Log.d(TAG, "calling native_inject_xtra_data");
- }
+ if (DEBUG) Log.d(TAG, "calling native_inject_xtra_data");
native_inject_xtra_data(data, data.length);
mXtraBackOff.reset();
}
@@ -1209,7 +1273,7 @@ public class GpsLocationProvider implements LocationProviderInterface {
if ("delete_aiding_data".equals(command)) {
result = deleteAidingData(extras);
} else if ("force_time_injection".equals(command)) {
- sendMessage(INJECT_NTP_TIME, 0, null);
+ requestUtcTime();
result = true;
} else if ("force_xtra_injection".equals(command)) {
if (mSupportsXtra) {
@@ -1536,51 +1600,20 @@ public class GpsLocationProvider implements LocationProviderInterface {
case GPS_REQUEST_AGPS_DATA_CONN:
if (DEBUG) Log.d(TAG, "GPS_REQUEST_AGPS_DATA_CONN");
Log.v(TAG, "Received SUPL IP addr[]: " + ipaddr);
- // Set mAGpsDataConnectionState before calling startUsingNetworkFeature
- // to avoid a race condition with handleUpdateNetworkState()
- mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING;
- int result = mConnMgr.startUsingNetworkFeature(
- ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_SUPL);
+ InetAddress connectionIpAddress = null;
if (ipaddr != null) {
try {
- mAGpsDataConnectionIpAddr = InetAddress.getByAddress(ipaddr);
- Log.v(TAG, "IP address converted to: " + mAGpsDataConnectionIpAddr);
+ connectionIpAddress = InetAddress.getByAddress(ipaddr);
+ if (DEBUG) Log.d(TAG, "IP address converted to: " + connectionIpAddress);
} catch (UnknownHostException e) {
Log.e(TAG, "Bad IP Address: " + ipaddr, e);
- mAGpsDataConnectionIpAddr = null;
- }
- }
-
- if (result == PhoneConstants.APN_ALREADY_ACTIVE) {
- if (DEBUG) Log.d(TAG, "PhoneConstants.APN_ALREADY_ACTIVE");
- if (mAGpsApn != null) {
- setRouting();
- native_agps_data_conn_open(mAGpsApn, mApnIpType);
- mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN;
- } else {
- Log.e(TAG, "mAGpsApn not set when receiving PhoneConstants.APN_ALREADY_ACTIVE");
- mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
- native_agps_data_conn_failed();
}
- } else if (result == PhoneConstants.APN_REQUEST_STARTED) {
- if (DEBUG) Log.d(TAG, "PhoneConstants.APN_REQUEST_STARTED");
- // Nothing to do here
- } else {
- if (DEBUG) Log.d(TAG, "startUsingNetworkFeature failed, value is " +
- result);
- mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
- native_agps_data_conn_failed();
}
+ sendMessage(REQUEST_SUPL_CONNECTION, 0 /*arg*/, connectionIpAddress);
break;
case GPS_RELEASE_AGPS_DATA_CONN:
if (DEBUG) Log.d(TAG, "GPS_RELEASE_AGPS_DATA_CONN");
- if (mAGpsDataConnectionState != AGPS_DATA_CONNECTION_CLOSED) {
- mConnMgr.stopUsingNetworkFeature(
- ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_SUPL);
- native_agps_data_conn_closed();
- mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
- mAGpsDataConnectionIpAddr = null;
- }
+ releaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN);
break;
case GPS_AGPS_DATA_CONNECTED:
if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONNECTED");
@@ -1596,6 +1629,10 @@ public class GpsLocationProvider implements LocationProviderInterface {
}
}
+ private void releaseSuplConnection(int connStatus) {
+ sendMessage(RELEASE_SUPL_CONNECTION, connStatus, null /*obj*/);
+ }
+
/**
* called from native code to report NMEA data received
*/
@@ -1921,8 +1958,8 @@ public class GpsLocationProvider implements LocationProviderInterface {
/**
* Called from native code to request utc time info
*/
-
private void requestUtcTime() {
+ if (DEBUG) Log.d(TAG, "utcTimeRequest");
sendMessage(INJECT_NTP_TIME, 0, null);
}
@@ -1990,7 +2027,13 @@ public class GpsLocationProvider implements LocationProviderInterface {
handleSetRequest(gpsRequest.request, gpsRequest.source);
break;
case UPDATE_NETWORK_STATE:
- handleUpdateNetworkState(msg.arg1);
+ handleUpdateNetworkState((Network) msg.obj);
+ break;
+ case REQUEST_SUPL_CONNECTION:
+ handleRequestSuplConnection((InetAddress) msg.obj);
+ break;
+ case RELEASE_SUPL_CONNECTION:
+ handleReleaseSuplConnection(msg.arg1);
break;
case INJECT_NTP_TIME:
handleInjectNtpTime();
@@ -2007,13 +2050,13 @@ public class GpsLocationProvider implements LocationProviderInterface {
mDownloadXtraDataPending = STATE_IDLE;
break;
case UPDATE_LOCATION:
- handleUpdateLocation((Location)msg.obj);
+ handleUpdateLocation((Location) msg.obj);
break;
case SUBSCRIPTION_OR_SIM_CHANGED:
subscriptionOrSimChanged(mContext);
break;
case INITIALIZE_HANDLER:
- initialize();
+ handleInitialize();
break;
}
if (msg.arg2 == 1) {
@@ -2027,7 +2070,7 @@ public class GpsLocationProvider implements LocationProviderInterface {
* It is in charge of loading properties and registering for events that will be posted to
* this handler.
*/
- private void initialize() {
+ private void handleInitialize() {
// load default GPS configuration
// (this configuration might change in the future based on SIM changes)
reloadGpsProperties(mContext, mProperties);
@@ -2067,8 +2110,6 @@ public class GpsLocationProvider implements LocationProviderInterface {
intentFilter = new IntentFilter();
intentFilter.addAction(ALARM_WAKEUP);
intentFilter.addAction(ALARM_TIMEOUT);
- intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
- intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION_SUPL);
intentFilter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
@@ -2076,6 +2117,14 @@ public class GpsLocationProvider implements LocationProviderInterface {
intentFilter.addAction(SIM_STATE_CHANGED);
mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this);
+ // register for connectivity change events, this is equivalent to the deprecated way of
+ // registering for CONNECTIVITY_ACTION broadcasts
+ NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder();
+ networkRequestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
+ networkRequestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
+ NetworkRequest networkRequest = networkRequestBuilder.build();
+ mConnMgr.registerNetworkCallback(networkRequest, mNetworkConnectivityCallback);
+
// listen for PASSIVE_PROVIDER updates
LocationManager locManager =
(LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
@@ -2140,15 +2189,11 @@ public class GpsLocationProvider implements LocationProviderInterface {
}
private int getApnIpType(String apn) {
+ ensureInHandlerThread();
if (apn == null) {
return APN_INVALID;
}
- // look for cached data to use
- if (apn.equals(mAGpsApn) && mApnIpType != APN_INVALID) {
- return mApnIpType;
- }
-
String selection = String.format("current = 1 and apn = '%s' and carrier_enabled = 1", apn);
Cursor cursor = null;
try {
@@ -2197,6 +2242,7 @@ public class GpsLocationProvider implements LocationProviderInterface {
return;
}
+ // TODO: replace the use of this deprecated API
boolean result = mConnMgr.requestRouteToHostAddress(
ConnectivityManager.TYPE_MOBILE_SUPL,
mAGpsDataConnectionIpAddr);
@@ -2208,6 +2254,61 @@ public class GpsLocationProvider implements LocationProviderInterface {
}
}
+ /**
+ * @return {@code true} if there is a data network available for outgoing connections,
+ * {@code false} otherwise.
+ */
+ private boolean isDataNetworkConnected() {
+ NetworkInfo activeNetworkInfo = mConnMgr.getActiveNetworkInfo();
+ return activeNetworkInfo != null && activeNetworkInfo.isConnected();
+ }
+
+ /**
+ * Ensures the calling function is running in the thread associated with {@link #mHandler}.
+ */
+ private void ensureInHandlerThread() {
+ if (mHandler != null && Looper.myLooper() == mHandler.getLooper()) {
+ return;
+ }
+ throw new RuntimeException("This method must run on the Handler thread.");
+ }
+
+ /**
+ * @return A string representing the current state stored in {@link #mAGpsDataConnectionState}.
+ */
+ private String agpsDataConnStateAsString() {
+ switch(mAGpsDataConnectionState) {
+ case AGPS_DATA_CONNECTION_CLOSED:
+ return "CLOSED";
+ case AGPS_DATA_CONNECTION_OPEN:
+ return "OPEN";
+ case AGPS_DATA_CONNECTION_OPENING:
+ return "OPENING";
+ default:
+ return "<Unknown>";
+ }
+ }
+
+ /**
+ * @return A string representing the given GPS_AGPS_DATA status.
+ */
+ private String agpsDataConnStatusAsString(int agpsDataConnStatus) {
+ switch (agpsDataConnStatus) {
+ case GPS_AGPS_DATA_CONNECTED:
+ return "CONNECTED";
+ case GPS_AGPS_DATA_CONN_DONE:
+ return "DONE";
+ case GPS_AGPS_DATA_CONN_FAILED:
+ return "FAILED";
+ case GPS_RELEASE_AGPS_DATA_CONN:
+ return "RELEASE";
+ case GPS_REQUEST_AGPS_DATA_CONN:
+ return "REQUEST";
+ default:
+ return "<Unknown>";
+ }
+ }
+
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
StringBuilder s = new StringBuilder();
@@ -2343,4 +2444,3 @@ public class GpsLocationProvider implements LocationProviderInterface {
// GNSS Configuration
private static native void native_configuration_update(String configData);
}
-
diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
index 96a5e0057d61..b5046056e913 100644
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -245,6 +245,8 @@ final class DefaultPermissionGrantPolicy {
if (verifierPackage != null
&& doesPackageSupportRuntimePermissions(verifierPackage)) {
grantRuntimePermissionsLPw(verifierPackage, STORAGE_PERMISSIONS, true, userId);
+ grantRuntimePermissionsLPw(verifierPackage, PHONE_PERMISSIONS, false, userId);
+ grantRuntimePermissionsLPw(verifierPackage, SMS_PERMISSIONS, false, userId);
}
// SetupWizard
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index b59b4b2586ee..d55697b40720 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -31,6 +31,19 @@ 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;
+
private final InstallerConnection mInstaller;
public Installer(Context context) {
@@ -75,26 +88,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) {
+ 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);
+ 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) {
+ 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);
+ 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 7024ec8b13b9..8be670e71a24 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -35,6 +35,10 @@ 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.InstructionSets.getAppDexInstructionSets;
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
@@ -71,7 +75,7 @@ final class PackageDexOptimizer {
* {@link PackageManagerService#mInstallLock}.
*/
int performDexOpt(PackageParser.Package pkg, String[] instructionSets,
- boolean forceDex, boolean defer, boolean inclDependencies) {
+ boolean forceDex, boolean defer, boolean inclDependencies, boolean bootComplete) {
ArraySet<String> done;
if (inclDependencies && (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null)) {
done = new ArraySet<String>();
@@ -86,7 +90,7 @@ final class PackageDexOptimizer {
mDexoptWakeLock.acquire();
}
try {
- return performDexOptLI(pkg, instructionSets, forceDex, defer, done);
+ return performDexOptLI(pkg, instructionSets, forceDex, defer, bootComplete, done);
} finally {
if (useLock) {
mDexoptWakeLock.release();
@@ -96,18 +100,19 @@ final class PackageDexOptimizer {
}
private int performDexOptLI(PackageParser.Package pkg, String[] targetInstructionSets,
- boolean forceDex, boolean defer, ArraySet<String> done) {
+ boolean forceDex, boolean defer, boolean bootComplete, ArraySet<String> done) {
final String[] instructionSets = targetInstructionSets != null ?
targetInstructionSets : getAppDexInstructionSets(pkg.applicationInfo);
if (done != null) {
done.add(pkg.packageName);
if (pkg.usesLibraries != null) {
- performDexOptLibsLI(pkg.usesLibraries, instructionSets, forceDex, defer, done);
+ performDexOptLibsLI(pkg.usesLibraries, instructionSets, forceDex, defer,
+ bootComplete, done);
}
if (pkg.usesOptionalLibraries != null) {
performDexOptLibsLI(pkg.usesOptionalLibraries, instructionSets, forceDex, defer,
- done);
+ bootComplete, done);
}
}
@@ -174,11 +179,15 @@ final class PackageDexOptimizer {
Log.i(TAG, "Running dexopt (" + dexoptType + ") on: " + path + " pkg="
+ pkg.applicationInfo.packageName + " isa=" + dexCodeInstructionSet
+ " vmSafeMode=" + vmSafeMode + " debuggable=" + debuggable
- + " oatDir = " + oatDir);
+ + " oatDir = " + oatDir + " bootComplete=" + bootComplete);
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);
final int ret = mPackageManagerService.mInstaller.dexopt(path, sharedGid,
- !pkg.isForwardLocked(), pkg.packageName, dexCodeInstructionSet,
- dexoptNeeded, vmSafeMode, debuggable, oatDir);
+ 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.
@@ -217,8 +226,7 @@ final class PackageDexOptimizer {
@Nullable
private String createOatDirIfSupported(PackageParser.Package pkg, String dexInstructionSet)
throws IOException {
- if ((pkg.isSystemApp() && !pkg.isUpdatedSystemApp()) || pkg.isForwardLocked()
- || pkg.applicationInfo.isExternalAsec()) {
+ if (!pkg.canHaveOatDir()) {
return null;
}
File codePath = new File(pkg.codePath);
@@ -236,12 +244,12 @@ final class PackageDexOptimizer {
}
private void performDexOptLibsLI(ArrayList<String> libs, String[] instructionSets,
- boolean forceDex, boolean defer, ArraySet<String> done) {
+ boolean forceDex, boolean defer, boolean bootComplete, ArraySet<String> done) {
for (String libName : libs) {
PackageParser.Package libPkg = mPackageManagerService.findSharedNonSystemLibrary(
libName);
if (libPkg != null && !done.contains(libName)) {
- performDexOptLI(libPkg, instructionSets, forceDex, defer, done);
+ performDexOptLI(libPkg, instructionSets, forceDex, defer, bootComplete, done);
}
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 82afdd7cd4e1..7a445a6dc6ae 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);
+ 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);
+ mInstaller.dexopt(path, Process.SYSTEM_UID, dexCodeInstructionSet,
+ dexoptNeeded, DEXOPT_PUBLIC /*dexFlags*/);
}
} catch (FileNotFoundException e) {
Slog.w(TAG, "Jar not found: " + path);
@@ -2292,7 +2295,8 @@ public class PackageManagerService extends IPackageManager.Stub {
// the rest of the commands above) because there's precious little we
// can do about it. A settings error is reported, though.
adjustCpuAbisForSharedUserLPw(setting.packages, null /* scanned package */,
- false /* force dexopt */, false /* defer dexopt */);
+ false /* force dexopt */, false /* defer dexopt */,
+ false /* boot complete */);
}
// Now that we know all the packages we are keeping,
@@ -4575,7 +4579,7 @@ public class PackageManagerService extends IPackageManager.Stub {
// Check for results that need to skip the current profile.
ResolveInfo xpResolveInfo = querySkipCurrentProfileIntents(matchingFilters, intent,
resolvedType, flags, userId);
- if (xpResolveInfo != null && isUserEnabled(xpResolveInfo.targetUserId)) {
+ if (xpResolveInfo != null) {
List<ResolveInfo> result = new ArrayList<ResolveInfo>(1);
result.add(xpResolveInfo);
return filterIfNotSystemUser(result, userId);
@@ -4667,8 +4671,8 @@ public class PackageManagerService extends IPackageManager.Stub {
int status = (int)(verificationState >> 32);
if (result == null) {
result = new CrossProfileDomainInfo();
- result.resolveInfo =
- createForwardingResolveInfo(new IntentFilter(), sourceUserId, parentUserId);
+ result.resolveInfo = createForwardingResolveInfoUnchecked(new IntentFilter(),
+ sourceUserId, parentUserId);
result.bestDomainVerificationStatus = status;
} else {
result.bestDomainVerificationStatus = bestDomainVerificationStatus(status,
@@ -4922,8 +4926,8 @@ public class PackageManagerService extends IPackageManager.Stub {
if ((filter.getFlags() & PackageManager.SKIP_CURRENT_PROFILE) != 0) {
// Checking if there are activities in the target user that can handle the
// intent.
- ResolveInfo resolveInfo = checkTargetCanHandle(filter, intent, resolvedType,
- flags, sourceUserId);
+ ResolveInfo resolveInfo = createForwardingResolveInfo(filter, intent,
+ resolvedType, flags, sourceUserId);
if (resolveInfo != null) {
return resolveInfo;
}
@@ -4950,8 +4954,8 @@ public class PackageManagerService extends IPackageManager.Stub {
&& !alreadyTriedUserIds.get(targetUserId)) {
// Checking if there are activities in the target user that can handle the
// intent.
- ResolveInfo resolveInfo = checkTargetCanHandle(filter, intent, resolvedType,
- flags, sourceUserId);
+ ResolveInfo resolveInfo = createForwardingResolveInfo(filter, intent,
+ resolvedType, flags, sourceUserId);
if (resolveInfo != null) return resolveInfo;
alreadyTriedUserIds.put(targetUserId, true);
}
@@ -4960,17 +4964,24 @@ public class PackageManagerService extends IPackageManager.Stub {
return null;
}
- private ResolveInfo checkTargetCanHandle(CrossProfileIntentFilter filter, Intent intent,
+ /**
+ * If the filter's target user can handle the intent and is enabled: returns a ResolveInfo that
+ * will forward the intent to the filter's target user.
+ * Otherwise, returns null.
+ */
+ private ResolveInfo createForwardingResolveInfo(CrossProfileIntentFilter filter, Intent intent,
String resolvedType, int flags, int sourceUserId) {
+ int targetUserId = filter.getTargetUserId();
List<ResolveInfo> resultTargetUser = mActivities.queryIntent(intent,
- resolvedType, flags, filter.getTargetUserId());
- if (resultTargetUser != null && !resultTargetUser.isEmpty()) {
- return createForwardingResolveInfo(filter, sourceUserId, filter.getTargetUserId());
+ resolvedType, flags, targetUserId);
+ if (resultTargetUser != null && !resultTargetUser.isEmpty()
+ && isUserEnabled(targetUserId)) {
+ return createForwardingResolveInfoUnchecked(filter, sourceUserId, targetUserId);
}
return null;
}
- private ResolveInfo createForwardingResolveInfo(IntentFilter filter,
+ private ResolveInfo createForwardingResolveInfoUnchecked(IntentFilter filter,
int sourceUserId, int targetUserId) {
ResolveInfo forwardingResolveInfo = new ResolveInfo();
long ident = Binder.clearCallingIdentity();
@@ -6148,41 +6159,6 @@ public class PackageManagerService extends IPackageManager.Stub {
it.remove();
}
}
- // Give priority to system apps.
- for (Iterator<PackageParser.Package> it = pkgs.iterator(); it.hasNext();) {
- PackageParser.Package pkg = it.next();
- if (isSystemApp(pkg) && !pkg.isUpdatedSystemApp()) {
- if (DEBUG_DEXOPT) {
- Log.i(TAG, "Adding system app " + sortedPkgs.size() + ": " + pkg.packageName);
- }
- sortedPkgs.add(pkg);
- it.remove();
- }
- }
- // Give priority to updated system apps.
- for (Iterator<PackageParser.Package> it = pkgs.iterator(); it.hasNext();) {
- PackageParser.Package pkg = it.next();
- if (pkg.isUpdatedSystemApp()) {
- if (DEBUG_DEXOPT) {
- Log.i(TAG, "Adding updated system app " + sortedPkgs.size() + ": " + pkg.packageName);
- }
- sortedPkgs.add(pkg);
- it.remove();
- }
- }
- // Give priority to apps that listen for boot complete.
- intent = new Intent(Intent.ACTION_BOOT_COMPLETED);
- pkgNames = getPackageNamesForIntent(intent, UserHandle.USER_SYSTEM);
- for (Iterator<PackageParser.Package> it = pkgs.iterator(); it.hasNext();) {
- PackageParser.Package pkg = it.next();
- if (pkgNames.contains(pkg.packageName)) {
- if (DEBUG_DEXOPT) {
- Log.i(TAG, "Adding boot app " + sortedPkgs.size() + ": " + pkg.packageName);
- }
- sortedPkgs.add(pkg);
- it.remove();
- }
- }
// Filter out packages that aren't recently used.
filterRecentlyUsedApps(pkgs);
// Add all remaining apps.
@@ -6274,7 +6250,8 @@ public class PackageManagerService extends IPackageManager.Stub {
PackageParser.Package p = pkg;
synchronized (mInstallLock) {
mPackageDexOptimizer.performDexOpt(p, null /* instruction sets */,
- false /* force dex */, false /* defer */, true /* include dependencies */);
+ false /* force dex */, false /* defer */, true /* include dependencies */,
+ false /* boot complete */);
}
}
@@ -6333,7 +6310,8 @@ public class PackageManagerService extends IPackageManager.Stub {
synchronized (mInstallLock) {
final String[] instructionSets = new String[] { targetInstructionSet };
int result = mPackageDexOptimizer.performDexOpt(p, instructionSets,
- false /* forceDex */, false /* defer */, true /* inclDependencies */);
+ false /* forceDex */, false /* defer */, true /* inclDependencies */,
+ true /* boot complete */);
return result == PackageDexOptimizer.DEX_OPT_PERFORMED;
}
} finally {
@@ -6383,7 +6361,8 @@ public class PackageManagerService extends IPackageManager.Stub {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
final int res = mPackageDexOptimizer.performDexOpt(pkg, instructionSets,
- true /*forceDex*/, false /* defer */, true /* inclDependencies */);
+ true /*forceDex*/, false /* defer */, true /* inclDependencies */,
+ true /* boot complete */);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
if (res != PackageDexOptimizer.DEX_OPT_PERFORMED) {
@@ -7192,14 +7171,15 @@ public class PackageManagerService extends IPackageManager.Stub {
// we can avoid redundant dexopts, and also to make sure we've got the
// code and package path correct.
adjustCpuAbisForSharedUserLPw(pkgSetting.sharedUser.packages,
- pkg, forceDex, (scanFlags & SCAN_DEFER_DEX) != 0);
+ pkg, forceDex, (scanFlags & SCAN_DEFER_DEX) != 0, true /* boot complete */);
}
if ((scanFlags & SCAN_NO_DEX) == 0) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
int result = mPackageDexOptimizer.performDexOpt(pkg, null /* instruction sets */,
- forceDex, (scanFlags & SCAN_DEFER_DEX) != 0, false /* inclDependencies */);
+ forceDex, (scanFlags & SCAN_DEFER_DEX) != 0, false /* inclDependencies */,
+ (scanFlags & SCAN_BOOTING) == 0);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
@@ -7279,7 +7259,8 @@ public class PackageManagerService extends IPackageManager.Stub {
PackageParser.Package clientPkg = clientLibPkgs.get(i);
int result = mPackageDexOptimizer.performDexOpt(clientPkg,
null /* instruction sets */, forceDex,
- (scanFlags & SCAN_DEFER_DEX) != 0, false);
+ (scanFlags & SCAN_DEFER_DEX) != 0, false,
+ (scanFlags & SCAN_BOOTING) == 0);
if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
throw new PackageManagerException(INSTALL_FAILED_DEXOPT,
"scanPackageLI failed to dexopt clientLibPkgs");
@@ -7835,7 +7816,8 @@ public class PackageManagerService extends IPackageManager.Stub {
* adds unnecessary complexity.
*/
private void adjustCpuAbisForSharedUserLPw(Set<PackageSetting> packagesForUser,
- PackageParser.Package scannedPackage, boolean forceDexOpt, boolean deferDexOpt) {
+ PackageParser.Package scannedPackage, boolean forceDexOpt, boolean deferDexOpt,
+ boolean bootComplete) {
String requiredInstructionSet = null;
if (scannedPackage != null && scannedPackage.applicationInfo.primaryCpuAbi != null) {
requiredInstructionSet = VMRuntime.getInstructionSet(
@@ -7901,7 +7883,8 @@ public class PackageManagerService extends IPackageManager.Stub {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
int result = mPackageDexOptimizer.performDexOpt(ps.pkg,
- null /* instruction sets */, forceDexOpt, deferDexOpt, true);
+ null /* instruction sets */, forceDexOpt, deferDexOpt, true,
+ bootComplete);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
@@ -12373,6 +12356,7 @@ public class PackageManagerService extends IPackageManager.Stub {
// Retrieve PackageSettings and parse package
final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY
+ | PackageParser.PARSE_ENFORCE_CODE
| (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0)
| (onExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0);
PackageParser pp = new PackageParser();
@@ -12590,8 +12574,8 @@ public class PackageManagerService extends IPackageManager.Stub {
int result = mPackageDexOptimizer
.performDexOpt(pkg, null /* instruction sets */, false /* forceDex */,
- false /* defer */, false /* inclDependencies */);
-
+ false /* defer */, false /* inclDependencies */,
+ true /*bootComplete*/);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
res.setError(INSTALL_FAILED_DEXOPT, "Dexopt failed for " + pkg.codePath);
@@ -13844,7 +13828,21 @@ public class PackageManagerService extends IPackageManager.Stub {
// TODO(multiArch): Extend getSizeInfo to look at *all* instruction sets, not
// just the primary.
String[] dexCodeInstructionSets = getDexCodeInstructionSets(getAppDexInstructionSets(ps));
- int res = mInstaller.getSizeInfo(p.volumeUuid, packageName, userHandle, p.baseCodePath,
+
+ String apkPath;
+ File packageDir = new File(p.codePath);
+
+ if (packageDir.isDirectory() && p.canHaveOatDir()) {
+ apkPath = packageDir.getAbsolutePath();
+ // If libDirRoot is inside a package dir, set it to null to avoid it being counted twice
+ if (libDirRoot != null && libDirRoot.startsWith(apkPath)) {
+ libDirRoot = null;
+ }
+ } else {
+ apkPath = p.baseCodePath;
+ }
+
+ int res = mInstaller.getSizeInfo(p.volumeUuid, packageName, userHandle, apkPath,
libDirRoot, publicSrcDir, asecPath, dexCodeInstructionSets, pStats);
if (res < 0) {
return false;
@@ -15880,14 +15878,28 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
- private void loadPrivatePackages(VolumeInfo vol) {
+ private void loadPrivatePackages(final VolumeInfo vol) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ loadPrivatePackagesInner(vol);
+ }
+ });
+ }
+
+ private void loadPrivatePackagesInner(VolumeInfo vol) {
final ArrayList<ApplicationInfo> loaded = new ArrayList<>();
final int parseFlags = mDefParseFlags | PackageParser.PARSE_EXTERNAL_STORAGE;
- synchronized (mInstallLock) {
+
+ final VersionInfo ver;
+ final List<PackageSetting> packages;
synchronized (mPackages) {
- final VersionInfo ver = mSettings.findOrCreateVersion(vol.fsUuid);
- final List<PackageSetting> packages = mSettings.getVolumePackagesLPr(vol.fsUuid);
- for (PackageSetting ps : packages) {
+ ver = mSettings.findOrCreateVersion(vol.fsUuid);
+ packages = mSettings.getVolumePackagesLPr(vol.fsUuid);
+ }
+
+ for (PackageSetting ps : packages) {
+ synchronized (mInstallLock) {
final PackageParser.Package pkg;
try {
pkg = scanPackageTracedLI(ps.codePath, parseFlags, SCAN_INITIAL, 0L, null);
@@ -15900,7 +15912,9 @@ public class PackageManagerService extends IPackageManager.Stub {
deleteCodeCacheDirsLI(ps.volumeUuid, ps.name);
}
}
+ }
+ synchronized (mPackages) {
int updateFlags = UPDATE_PERMISSIONS_ALL;
if (ver.sdkVersion != mSdkVersion) {
logCriticalInfo(Log.INFO, "Platform changed from " + ver.sdkVersion + " to "
@@ -15914,13 +15928,21 @@ public class PackageManagerService extends IPackageManager.Stub {
mSettings.writeLPr();
}
- }
if (DEBUG_INSTALL) Slog.d(TAG, "Loaded packages " + loaded);
sendResourcesChangedBroadcast(true, false, loaded, null);
}
- private void unloadPrivatePackages(VolumeInfo vol) {
+ private void unloadPrivatePackages(final VolumeInfo vol) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ unloadPrivatePackagesInner(vol);
+ }
+ });
+ }
+
+ private void unloadPrivatePackagesInner(VolumeInfo vol) {
final ArrayList<ApplicationInfo> unloaded = new ArrayList<>();
synchronized (mInstallLock) {
synchronized (mPackages) {
diff --git a/services/core/java/com/android/server/policy/BarController.java b/services/core/java/com/android/server/policy/BarController.java
index 9095f57b175a..051b7fb17d69 100644
--- a/services/core/java/com/android/server/policy/BarController.java
+++ b/services/core/java/com/android/server/policy/BarController.java
@@ -258,7 +258,7 @@ public class BarController {
vis &= ~View.SYSTEM_UI_FLAG_LOW_PROFILE; // never show transient bars in low profile
}
if ((vis & mTranslucentFlag) != 0 || (oldVis & mTranslucentFlag) != 0 ||
- ((vis | oldVis) & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0) {
+ ((vis | oldVis) & View.SYSTEM_UI_TRANSPARENT) != 0) {
mLastTranslucent = SystemClock.uptimeMillis();
}
return vis;
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 63d0ba131aee..dbc3970cf4cf 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -266,9 +266,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
WindowManagerFuncs mWindowManagerFuncs;
WindowManagerInternal mWindowManagerInternal;
PowerManager mPowerManager;
- PowerManagerInternal mPowerManagerInternal;
ActivityManagerInternal mActivityManagerInternal;
DreamManagerInternal mDreamManagerInternal;
+ PowerManagerInternal mPowerManagerInternal;
IStatusBarService mStatusBarService;
boolean mPreloadedRecentApps;
final Object mServiceAquireLock = new Object();
@@ -1343,8 +1343,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
mDreamManagerInternal = LocalServices.getService(DreamManagerInternal.class);
- mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
+ mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
// Init display burn-in protection
boolean burnInProtectionEnabled = context.getResources().getBoolean(
@@ -1520,6 +1520,13 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
@Override
+ public void onFling(int duration) {
+ if (mPowerManagerInternal != null) {
+ mPowerManagerInternal.powerHint(
+ PowerManagerInternal.POWER_HINT_INTERACTION, duration);
+ }
+ }
+ @Override
public void onDebug() {
// no-op
}
@@ -1996,6 +2003,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
case TYPE_SYSTEM_DIALOG:
case TYPE_VOLUME_OVERLAY:
case TYPE_PRIVATE_PRESENTATION:
+ case TYPE_DOCK_DIVIDER:
break;
}
@@ -2127,54 +2135,56 @@ 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 14;
- case TYPE_STATUS_BAR_SUB_PANEL:
return 15;
- case TYPE_STATUS_BAR:
+ case TYPE_STATUS_BAR_SUB_PANEL:
return 16;
- case TYPE_STATUS_BAR_PANEL:
+ case TYPE_STATUS_BAR:
return 17;
- case TYPE_KEYGUARD_DIALOG:
+ case TYPE_STATUS_BAR_PANEL:
return 18;
+ case TYPE_KEYGUARD_DIALOG:
+ return 19;
case TYPE_VOLUME_OVERLAY:
// the on-screen volume indicator and controller shown when the user
// changes the device volume
- return 19;
+ return 20;
case TYPE_SYSTEM_OVERLAY:
// the on-screen volume indicator and controller shown when the user
// changes the device volume
- return 20;
+ return 21;
case TYPE_NAVIGATION_BAR:
// the navigation bar, if available, shows atop most things
- return 21;
+ return 22;
case TYPE_NAVIGATION_BAR_PANEL:
// some panels (e.g. search) need to show on top of the navigation bar
- return 22;
+ return 23;
case TYPE_SYSTEM_ERROR:
// system-level error dialogs
- return 23;
+ return 24;
case TYPE_MAGNIFICATION_OVERLAY:
// used to highlight the magnified portion of a display
- return 24;
+ return 25;
case TYPE_DISPLAY_OVERLAY:
// used to simulate secondary display devices
- return 25;
+ return 26;
case TYPE_DRAG:
// the drag layer: input for drag-and-drop is associated with this window,
// which sits above all other focusable windows
- return 26;
+ return 27;
case TYPE_ACCESSIBILITY_OVERLAY:
// overlay put by accessibility services to intercept user interaction
- return 27;
- case TYPE_SECURE_SYSTEM_OVERLAY:
return 28;
- case TYPE_BOOT_PROGRESS:
+ case TYPE_SECURE_SYSTEM_OVERLAY:
return 29;
+ case TYPE_BOOT_PROGRESS:
+ return 30;
case TYPE_POINTER:
// the (mouse) pointer layer
- return 30;
+ return 31;
}
Log.e(TAG, "Unknown window type: " + type);
return 2;
@@ -2264,6 +2274,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
case TYPE_WALLPAPER:
case TYPE_DREAM:
case TYPE_KEYGUARD_SCRIM:
+ case TYPE_DOCK_DIVIDER:
return false;
default:
// Hide only windows below the keyguard host window.
@@ -3570,7 +3581,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
final Rect of = mTmpOverscanFrame;
final Rect vf = mTmpVisibleFrame;
final Rect dcf = mTmpDecorFrame;
- final Rect osf = mTmpOutsetFrame;
pf.left = df.left = of.left = vf.left = mDockLeft;
pf.top = df.top = of.top = vf.top = mDockTop;
pf.right = df.right = of.right = vf.right = mDockRight;
@@ -3612,150 +3622,163 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// then take that into account.
navVisible |= !canHideNavigationBar();
- boolean updateSysUiVisibility = false;
- if (mNavigationBar != null) {
- boolean transientNavBarShowing = mNavigationBarController.isTransientShowing();
- // Force the navigation bar to its appropriate place and
- // size. We need to do this directly, instead of relying on
- // it to bubble up from the nav bar, because this needs to
- // change atomically with screen rotations.
- mNavigationBarOnBottom = (!mNavigationBarCanMove || displayWidth < displayHeight);
- if (mNavigationBarOnBottom) {
- // It's a system nav bar or a portrait screen; nav bar goes on bottom.
- int top = displayHeight - overscanBottom
- - mNavigationBarHeightForRotation[displayRotation];
- mTmpNavigationFrame.set(0, top, displayWidth, displayHeight - overscanBottom);
- mStableBottom = mStableFullscreenBottom = mTmpNavigationFrame.top;
- if (transientNavBarShowing) {
- mNavigationBarController.setBarShowingLw(true);
- } else if (navVisible) {
- mNavigationBarController.setBarShowingLw(true);
- mDockBottom = mTmpNavigationFrame.top;
- mRestrictedScreenHeight = mDockBottom - mRestrictedScreenTop;
- mRestrictedOverscanScreenHeight = mDockBottom - mRestrictedOverscanScreenTop;
- } else {
- // We currently want to hide the navigation UI.
- mNavigationBarController.setBarShowingLw(false);
- }
- if (navVisible && !navTranslucent && !navAllowedHidden
- && !mNavigationBar.isAnimatingLw()
- && !mNavigationBarController.wasRecentlyTranslucent()) {
- // If the opaque nav bar is currently requested to be visible,
- // and not in the process of animating on or off, then
- // we can tell the app that it is covered by it.
- mSystemBottom = mTmpNavigationFrame.top;
- }
- } else {
- // Landscape screen; nav bar goes to the right.
- int left = displayWidth - overscanRight
- - mNavigationBarWidthForRotation[displayRotation];
- mTmpNavigationFrame.set(left, 0, displayWidth - overscanRight, displayHeight);
- mStableRight = mStableFullscreenRight = mTmpNavigationFrame.left;
- if (transientNavBarShowing) {
- mNavigationBarController.setBarShowingLw(true);
- } else if (navVisible) {
- mNavigationBarController.setBarShowingLw(true);
- mDockRight = mTmpNavigationFrame.left;
- mRestrictedScreenWidth = mDockRight - mRestrictedScreenLeft;
- mRestrictedOverscanScreenWidth = mDockRight - mRestrictedOverscanScreenLeft;
- } else {
- // We currently want to hide the navigation UI.
- mNavigationBarController.setBarShowingLw(false);
- }
- if (navVisible && !navTranslucent && !navAllowedHidden
- && !mNavigationBar.isAnimatingLw()
- && !mNavigationBarController.wasRecentlyTranslucent()) {
- // If the nav bar is currently requested to be visible,
- // and not in the process of animating on or off, then
- // we can tell the app that it is covered by it.
- mSystemRight = mTmpNavigationFrame.left;
- }
- }
- // Make sure the content and current rectangles are updated to
- // account for the restrictions from the navigation bar.
- mContentTop = mVoiceContentTop = mCurTop = mDockTop;
- mContentBottom = mVoiceContentBottom = mCurBottom = mDockBottom;
- mContentLeft = mVoiceContentLeft = mCurLeft = mDockLeft;
- mContentRight = mVoiceContentRight = mCurRight = mDockRight;
- mStatusBarLayer = mNavigationBar.getSurfaceLayer();
- // And compute the final frame.
- mNavigationBar.computeFrameLw(mTmpNavigationFrame, mTmpNavigationFrame,
- mTmpNavigationFrame, mTmpNavigationFrame, mTmpNavigationFrame, dcf,
- mTmpNavigationFrame, mTmpNavigationFrame);
- if (DEBUG_LAYOUT) Slog.i(TAG, "mNavigationBar frame: " + mTmpNavigationFrame);
- if (mNavigationBarController.checkHiddenLw()) {
- updateSysUiVisibility = true;
- }
- }
+ boolean updateSysUiVisibility = layoutNavigationBar(displayWidth, displayHeight,
+ displayRotation, overscanRight, overscanBottom, dcf, navVisible, navTranslucent,
+ navAllowedHidden);
if (DEBUG_LAYOUT) Slog.i(TAG, String.format("mDock rect: (%d,%d - %d,%d)",
mDockLeft, mDockTop, mDockRight, mDockBottom));
+ updateSysUiVisibility |= layoutStatusBar(pf, df, of, vf, dcf, sysui, isKeyguardShowing);
+ if (updateSysUiVisibility) {
+ updateSystemUiVisibilityLw();
+ }
+ }
+ }
- // decide where the status bar goes ahead of time
- if (mStatusBar != null) {
- // apply any navigation bar insets
- pf.left = df.left = of.left = mUnrestrictedScreenLeft;
- pf.top = df.top = of.top = mUnrestrictedScreenTop;
- pf.right = df.right = of.right = mUnrestrictedScreenWidth + mUnrestrictedScreenLeft;
- pf.bottom = df.bottom = of.bottom = mUnrestrictedScreenHeight
- + mUnrestrictedScreenTop;
- vf.left = mStableLeft;
- vf.top = mStableTop;
- vf.right = mStableRight;
- vf.bottom = mStableBottom;
-
- mStatusBarLayer = mStatusBar.getSurfaceLayer();
-
- // Let the status bar determine its size.
- mStatusBar.computeFrameLw(pf /* parentFrame */, df /* displayFrame */,
- vf /* overlayFrame */, vf /* contentFrame */, vf /* visibleFrame */,
- dcf /* decorFrame */, vf /* stableFrame */, vf /* outsetFrame */);
-
- // For layout, the status bar is always at the top with our fixed height.
- mStableTop = mUnrestrictedScreenTop + mStatusBarHeight;
-
- boolean statusBarTransient = (sysui & View.STATUS_BAR_TRANSIENT) != 0;
- boolean statusBarTranslucent = (sysui
- & (View.STATUS_BAR_TRANSLUCENT | View.SYSTEM_UI_TRANSPARENT)) != 0;
- if (!isKeyguardShowing) {
- statusBarTranslucent &= areTranslucentBarsAllowed();
- }
+ private boolean layoutStatusBar(Rect pf, Rect df, Rect of, Rect vf, Rect dcf, int sysui,
+ boolean isKeyguardShowing) {
+ // decide where the status bar goes ahead of time
+ if (mStatusBar != null) {
+ // apply any navigation bar insets
+ pf.left = df.left = of.left = mUnrestrictedScreenLeft;
+ pf.top = df.top = of.top = mUnrestrictedScreenTop;
+ pf.right = df.right = of.right = mUnrestrictedScreenWidth + mUnrestrictedScreenLeft;
+ pf.bottom = df.bottom = of.bottom = mUnrestrictedScreenHeight
+ + mUnrestrictedScreenTop;
+ vf.left = mStableLeft;
+ vf.top = mStableTop;
+ vf.right = mStableRight;
+ vf.bottom = mStableBottom;
+
+ mStatusBarLayer = mStatusBar.getSurfaceLayer();
+
+ // Let the status bar determine its size.
+ mStatusBar.computeFrameLw(pf /* parentFrame */, df /* displayFrame */,
+ vf /* overlayFrame */, vf /* contentFrame */, vf /* visibleFrame */,
+ dcf /* decorFrame */, vf /* stableFrame */, vf /* outsetFrame */);
+
+ // For layout, the status bar is always at the top with our fixed height.
+ mStableTop = mUnrestrictedScreenTop + mStatusBarHeight;
- // If the status bar is hidden, we don't want to cause
- // windows behind it to scroll.
- if (mStatusBar.isVisibleLw() && !statusBarTransient) {
- // Status bar may go away, so the screen area it occupies
- // is available to apps but just covering them when the
- // status bar is visible.
- mDockTop = mUnrestrictedScreenTop + mStatusBarHeight;
+ boolean statusBarTransient = (sysui & View.STATUS_BAR_TRANSIENT) != 0;
+ boolean statusBarTranslucent = (sysui
+ & (View.STATUS_BAR_TRANSLUCENT | View.SYSTEM_UI_TRANSPARENT)) != 0;
+ if (!isKeyguardShowing) {
+ statusBarTranslucent &= areTranslucentBarsAllowed();
+ }
+
+ // If the status bar is hidden, we don't want to cause
+ // windows behind it to scroll.
+ if (mStatusBar.isVisibleLw() && !statusBarTransient) {
+ // Status bar may go away, so the screen area it occupies
+ // is available to apps but just covering them when the
+ // status bar is visible.
+ mDockTop = mUnrestrictedScreenTop + mStatusBarHeight;
- mContentTop = mVoiceContentTop = mCurTop = mDockTop;
- mContentBottom = mVoiceContentBottom = mCurBottom = mDockBottom;
- mContentLeft = mVoiceContentLeft = mCurLeft = mDockLeft;
- mContentRight = mVoiceContentRight = mCurRight = mDockRight;
+ mContentTop = mVoiceContentTop = mCurTop = mDockTop;
+ mContentBottom = mVoiceContentBottom = mCurBottom = mDockBottom;
+ mContentLeft = mVoiceContentLeft = mCurLeft = mDockLeft;
+ mContentRight = mVoiceContentRight = mCurRight = mDockRight;
- if (DEBUG_LAYOUT) Slog.v(TAG, "Status bar: " +
+ if (DEBUG_LAYOUT) Slog.v(TAG, "Status bar: " +
String.format(
- "dock=[%d,%d][%d,%d] content=[%d,%d][%d,%d] cur=[%d,%d][%d,%d]",
- mDockLeft, mDockTop, mDockRight, mDockBottom,
- mContentLeft, mContentTop, mContentRight, mContentBottom,
- mCurLeft, mCurTop, mCurRight, mCurBottom));
+ "dock=[%d,%d][%d,%d] content=[%d,%d][%d,%d] cur=[%d,%d][%d,%d]",
+ mDockLeft, mDockTop, mDockRight, mDockBottom,
+ mContentLeft, mContentTop, mContentRight, mContentBottom,
+ mCurLeft, mCurTop, mCurRight, mCurBottom));
+ }
+ if (mStatusBar.isVisibleLw() && !mStatusBar.isAnimatingLw()
+ && !statusBarTransient && !statusBarTranslucent
+ && !mStatusBarController.wasRecentlyTranslucent()) {
+ // If the opaque status bar is currently requested to be visible,
+ // and not in the process of animating on or off, then
+ // we can tell the app that it is covered by it.
+ mSystemTop = mUnrestrictedScreenTop + mStatusBarHeight;
+ }
+ if (mStatusBarController.checkHiddenLw()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean layoutNavigationBar(int displayWidth, int displayHeight, int displayRotation,
+ int overscanRight, int overscanBottom, Rect dcf, boolean navVisible,
+ boolean navTranslucent, boolean navAllowedHidden) {
+ if (mNavigationBar != null) {
+ boolean transientNavBarShowing = mNavigationBarController.isTransientShowing();
+ // Force the navigation bar to its appropriate place and
+ // size. We need to do this directly, instead of relying on
+ // it to bubble up from the nav bar, because this needs to
+ // change atomically with screen rotations.
+ mNavigationBarOnBottom = (!mNavigationBarCanMove || displayWidth < displayHeight);
+ if (mNavigationBarOnBottom) {
+ // It's a system nav bar or a portrait screen; nav bar goes on bottom.
+ int top = displayHeight - overscanBottom
+ - mNavigationBarHeightForRotation[displayRotation];
+ mTmpNavigationFrame.set(0, top, displayWidth, displayHeight - overscanBottom);
+ mStableBottom = mStableFullscreenBottom = mTmpNavigationFrame.top;
+ if (transientNavBarShowing) {
+ mNavigationBarController.setBarShowingLw(true);
+ } else if (navVisible) {
+ mNavigationBarController.setBarShowingLw(true);
+ mDockBottom = mTmpNavigationFrame.top;
+ mRestrictedScreenHeight = mDockBottom - mRestrictedScreenTop;
+ mRestrictedOverscanScreenHeight = mDockBottom - mRestrictedOverscanScreenTop;
+ } else {
+ // We currently want to hide the navigation UI.
+ mNavigationBarController.setBarShowingLw(false);
}
- if (mStatusBar.isVisibleLw() && !mStatusBar.isAnimatingLw()
- && !statusBarTransient && !statusBarTranslucent
- && !mStatusBarController.wasRecentlyTranslucent()) {
- // If the opaque status bar is currently requested to be visible,
+ if (navVisible && !navTranslucent && !navAllowedHidden
+ && !mNavigationBar.isAnimatingLw()
+ && !mNavigationBarController.wasRecentlyTranslucent()) {
+ // If the opaque nav bar is currently requested to be visible,
// and not in the process of animating on or off, then
// we can tell the app that it is covered by it.
- mSystemTop = mUnrestrictedScreenTop + mStatusBarHeight;
+ mSystemBottom = mTmpNavigationFrame.top;
}
- if (mStatusBarController.checkHiddenLw()) {
- updateSysUiVisibility = true;
+ } else {
+ // Landscape screen; nav bar goes to the right.
+ int left = displayWidth - overscanRight
+ - mNavigationBarWidthForRotation[displayRotation];
+ mTmpNavigationFrame.set(left, 0, displayWidth - overscanRight, displayHeight);
+ mStableRight = mStableFullscreenRight = mTmpNavigationFrame.left;
+ if (transientNavBarShowing) {
+ mNavigationBarController.setBarShowingLw(true);
+ } else if (navVisible) {
+ mNavigationBarController.setBarShowingLw(true);
+ mDockRight = mTmpNavigationFrame.left;
+ mRestrictedScreenWidth = mDockRight - mRestrictedScreenLeft;
+ mRestrictedOverscanScreenWidth = mDockRight - mRestrictedOverscanScreenLeft;
+ } else {
+ // We currently want to hide the navigation UI.
+ mNavigationBarController.setBarShowingLw(false);
+ }
+ if (navVisible && !navTranslucent && !navAllowedHidden
+ && !mNavigationBar.isAnimatingLw()
+ && !mNavigationBarController.wasRecentlyTranslucent()) {
+ // If the nav bar is currently requested to be visible,
+ // and not in the process of animating on or off, then
+ // we can tell the app that it is covered by it.
+ mSystemRight = mTmpNavigationFrame.left;
}
}
- if (updateSysUiVisibility) {
- updateSystemUiVisibilityLw();
+ // Make sure the content and current rectangles are updated to
+ // account for the restrictions from the navigation bar.
+ mContentTop = mVoiceContentTop = mCurTop = mDockTop;
+ mContentBottom = mVoiceContentBottom = mCurBottom = mDockBottom;
+ mContentLeft = mVoiceContentLeft = mCurLeft = mDockLeft;
+ mContentRight = mVoiceContentRight = mCurRight = mDockRight;
+ mStatusBarLayer = mNavigationBar.getSurfaceLayer();
+ // And compute the final frame.
+ mNavigationBar.computeFrameLw(mTmpNavigationFrame, mTmpNavigationFrame,
+ mTmpNavigationFrame, mTmpNavigationFrame, mTmpNavigationFrame, dcf,
+ mTmpNavigationFrame, mTmpNavigationFrame);
+ if (DEBUG_LAYOUT) Slog.i(TAG, "mNavigationBar frame: " + mTmpNavigationFrame);
+ if (mNavigationBarController.checkHiddenLw()) {
+ return true;
}
}
+ return false;
}
/** {@inheritDoc} */
@@ -4409,6 +4432,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
if (attrs.type == TYPE_STATUS_BAR) {
if ((attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
mForceStatusBarFromKeyguard = true;
+ mShowingLockscreen = true;
}
if ((attrs.privateFlags & PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT) != 0) {
mForceStatusBarTransparent = true;
@@ -4429,9 +4453,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mForceStatusBar = true;
}
}
- if ((attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
- mShowingLockscreen = true;
- }
if (attrs.type == TYPE_DREAM) {
// If the lockscreen was showing when the dream started then wait
// for the dream to draw before hiding the lockscreen.
@@ -6114,6 +6135,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mKeyguardDelegate.bindService(mContext);
mKeyguardDelegate.onBootCompleted();
}
+ mSystemGestures.systemReady();
}
/** {@inheritDoc} */
@@ -7061,5 +7083,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
if (mBurnInProtectionHelper != null) {
mBurnInProtectionHelper.dump(prefix, pw);
}
+ if (mKeyguardDelegate != null) {
+ mKeyguardDelegate.dump(prefix, pw);
+ }
}
}
diff --git a/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java b/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java
index 97831d10bdad..4ae3154c6771 100644
--- a/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java
+++ b/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java
@@ -17,9 +17,14 @@
package com.android.server.policy;
import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.SystemClock;
import android.util.Slog;
+import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.WindowManagerPolicy.PointerEventListener;
+import android.widget.OverScroller;
/*
* Listens for system-wide input gestures, firing callbacks when detected.
@@ -31,12 +36,14 @@ public class SystemGesturesPointerEventListener implements PointerEventListener
private static final long SWIPE_TIMEOUT_MS = 500;
private static final int MAX_TRACKED_POINTERS = 32; // max per input system
private static final int UNTRACKED_POINTER = -1;
+ private static final int MAX_FLING_TIME_MILLIS = 5000;
private static final int SWIPE_NONE = 0;
private static final int SWIPE_FROM_TOP = 1;
private static final int SWIPE_FROM_BOTTOM = 2;
private static final int SWIPE_FROM_RIGHT = 3;
+ private final Context mContext;
private final int mSwipeStartThreshold;
private final int mSwipeDistanceThreshold;
private final Callbacks mCallbacks;
@@ -45,14 +52,19 @@ public class SystemGesturesPointerEventListener implements PointerEventListener
private final float[] mDownY = new float[MAX_TRACKED_POINTERS];
private final long[] mDownTime = new long[MAX_TRACKED_POINTERS];
+ private GestureDetector mGestureDetector;
+ private OverScroller mOverscroller;
+
int screenHeight;
int screenWidth;
private int mDownPointers;
private boolean mSwipeFireable;
private boolean mDebugFireable;
private boolean mMouseHoveringAtEdge;
+ private long mLastFlingTime;
public SystemGesturesPointerEventListener(Context context, Callbacks callbacks) {
+ mContext = context;
mCallbacks = checkNull("callbacks", callbacks);
mSwipeStartThreshold = checkNull("context", context).getResources()
.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
@@ -68,8 +80,17 @@ public class SystemGesturesPointerEventListener implements PointerEventListener
return arg;
}
+ public void systemReady() {
+ Handler h = new Handler(Looper.myLooper());
+ mGestureDetector = new GestureDetector(mContext, new FlingGestureDetector(), h);
+ mOverscroller = new OverScroller(mContext);
+ }
+
@Override
public void onPointerEvent(MotionEvent event) {
+ if (mGestureDetector != null) {
+ mGestureDetector.onTouchEvent(event);
+ }
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
mSwipeFireable = true;
@@ -211,10 +232,40 @@ public class SystemGesturesPointerEventListener implements PointerEventListener
return SWIPE_NONE;
}
+ private final class FlingGestureDetector extends GestureDetector.SimpleOnGestureListener {
+ @Override
+ public boolean onSingleTapUp(MotionEvent e) {
+ if (!mOverscroller.isFinished()) {
+ mOverscroller.forceFinished(true);
+ }
+ return true;
+ }
+ @Override
+ public boolean onFling(MotionEvent down, MotionEvent up,
+ float velocityX, float velocityY) {
+ mOverscroller.computeScrollOffset();
+ long now = SystemClock.uptimeMillis();
+
+ if (mLastFlingTime != 0 && now > mLastFlingTime + MAX_FLING_TIME_MILLIS) {
+ mOverscroller.forceFinished(true);
+ }
+ mOverscroller.fling(0, 0, (int)velocityX, (int)velocityY,
+ Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE);
+ int duration = mOverscroller.getDuration();
+ if (duration > MAX_FLING_TIME_MILLIS) {
+ duration = MAX_FLING_TIME_MILLIS;
+ }
+ mLastFlingTime = now;
+ mCallbacks.onFling(duration);
+ return true;
+ }
+ }
+
interface Callbacks {
void onSwipeFromTop();
void onSwipeFromBottom();
void onSwipeFromRight();
+ void onFling(int durationMs);
void onDown();
void onUpOrCancel();
void onMouseHoverAtTop();
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index 6b45941d91ec..c0dfbcbb01ab 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -23,6 +23,8 @@ import com.android.internal.policy.IKeyguardDrawnCallback;
import com.android.internal.policy.IKeyguardExitCallback;
import com.android.internal.policy.IKeyguardService;
+import java.io.PrintWriter;
+
/**
* A local class that keeps a cache of keyguard state that can be restored in the event
* keyguard crashes. It currently also allows runtime-selectable
@@ -127,7 +129,7 @@ public class KeyguardServiceDelegate {
intent.setComponent(keyguardComponent);
if (!context.bindServiceAsUser(intent, mKeyguardConnection,
- Context.BIND_AUTO_CREATE, UserHandle.OWNER)) {
+ Context.BIND_AUTO_CREATE, UserHandle.SYSTEM)) {
Log.v(TAG, "*** Keyguard: can't bind to " + keyguardComponent);
mKeyguardState.showing = false;
mKeyguardState.showingAndNotOccluded = false;
@@ -393,4 +395,26 @@ public class KeyguardServiceDelegate {
mKeyguardService.onActivityDrawn();
}
}
+
+ public void dump(String prefix, PrintWriter pw) {
+ pw.println(prefix + TAG);
+ prefix += " ";
+ pw.println(prefix + "showing=" + mKeyguardState.showing);
+ pw.println(prefix + "showingAndNotOccluded=" + mKeyguardState.showingAndNotOccluded);
+ pw.println(prefix + "inputRestricted=" + mKeyguardState.inputRestricted);
+ pw.println(prefix + "occluded=" + mKeyguardState.occluded);
+ pw.println(prefix + "secure=" + mKeyguardState.secure);
+ pw.println(prefix + "dreaming=" + mKeyguardState.dreaming);
+ pw.println(prefix + "systemIsReady=" + mKeyguardState.systemIsReady);
+ pw.println(prefix + "deviceHasKeyguard=" + mKeyguardState.deviceHasKeyguard);
+ pw.println(prefix + "enabled=" + mKeyguardState.enabled);
+ pw.println(prefix + "offReason=" + mKeyguardState.offReason);
+ pw.println(prefix + "currentUser=" + mKeyguardState.currentUser);
+ pw.println(prefix + "bootCompleted=" + mKeyguardState.bootCompleted);
+ pw.println(prefix + "screenState=" + mKeyguardState.screenState);
+ pw.println(prefix + "interactiveState=" + mKeyguardState.interactiveState);
+ if (mKeyguardService != null) {
+ mKeyguardService.dump(prefix, pw);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
index cd88b664e2f8..429b18866a61 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
@@ -27,6 +27,8 @@ import com.android.internal.policy.IKeyguardExitCallback;
import com.android.internal.policy.IKeyguardService;
import com.android.internal.policy.IKeyguardStateCallback;
+import java.io.PrintWriter;
+
/**
* A wrapper class for KeyguardService. It implements IKeyguardService to ensure the interface
* remains consistent.
@@ -239,4 +241,8 @@ public class KeyguardServiceWrapper implements IKeyguardService {
public boolean isInputRestricted() {
return mKeyguardStateMonitor.isInputRestricted();
}
+
+ public void dump(String prefix, PrintWriter pw) {
+ mKeyguardStateMonitor.dump(prefix, pw);
+ }
} \ No newline at end of file
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
index f1f9c5087aa7..30cff039f11a 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
@@ -25,6 +25,8 @@ import com.android.internal.policy.IKeyguardService;
import com.android.internal.policy.IKeyguardStateCallback;
import com.android.internal.widget.LockPatternUtils;
+import java.io.PrintWriter;
+
/**
* Maintains a cached copy of Keyguard's state.
* @hide
@@ -90,4 +92,13 @@ public class KeyguardStateMonitor extends IKeyguardStateCallback.Stub {
public void onInputRestrictedStateChanged(boolean inputRestricted) {
mInputRestricted = inputRestricted;
}
+
+ public void dump(String prefix, PrintWriter pw) {
+ pw.println(prefix + TAG);
+ prefix += " ";
+ pw.println(prefix + "mIsShowing=" + mIsShowing);
+ pw.println(prefix + "mSimSecure=" + mSimSecure);
+ pw.println(prefix + "mInputRestricted=" + mInputRestricted);
+ pw.println(prefix + "mCurrentUserId=" + mCurrentUserId);
+ }
} \ No newline at end of file
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 4e702aa88a52..a0a31c0d8a0c 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -76,6 +76,7 @@ import java.util.Arrays;
import libcore.util.Objects;
+import static android.os.PowerManagerInternal.POWER_HINT_INTERACTION;
import static android.os.PowerManagerInternal.WAKEFULNESS_ASLEEP;
import static android.os.PowerManagerInternal.WAKEFULNESS_AWAKE;
import static android.os.PowerManagerInternal.WAKEFULNESS_DREAMING;
@@ -150,7 +151,6 @@ public final class PowerManagerService extends SystemService
private static final int SCREEN_BRIGHTNESS_BOOST_TIMEOUT = 5 * 1000;
// Power hints defined in hardware/libhardware/include/hardware/power.h.
- private static final int POWER_HINT_INTERACTION = 2;
private static final int POWER_HINT_LOW_POWER = 5;
// Power features defined in hardware/libhardware/include/hardware/power.h.
@@ -1577,6 +1577,13 @@ public final class PowerManagerService extends SystemService
}
if (mUserActivitySummary != USER_ACTIVITY_SCREEN_DREAM && userInactiveOverride) {
+ if ((mUserActivitySummary &
+ (USER_ACTIVITY_SCREEN_BRIGHT | USER_ACTIVITY_SCREEN_DIM)) != 0) {
+ // Device is being kept awake by recent user activity
+ long savedWakeTimeMs = now - nextTimeout;
+ EventLog.writeEvent(
+ EventLogTags.POWER_SOFT_SLEEP_REQUESTED, savedWakeTimeMs);
+ }
mUserActivitySummary = USER_ACTIVITY_SCREEN_DREAM;
nextTimeout = -1;
}
@@ -3570,5 +3577,10 @@ public final class PowerManagerService extends SystemService
public void uidGone(int uid) {
uidGoneInternal(uid);
}
+
+ @Override
+ public void powerHint(int hintId, int data) {
+ powerHintInternal(hintId, data);
+ }
}
}
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 87dc6c4c3e72..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) {
}
}
@@ -305,9 +305,8 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
throw new SecurityException("invalid status bar icon slot: " + slot);
}
- StatusBarIcon icon = new StatusBarIcon(iconPackage, UserHandle.OWNER, iconId,
- iconLevel, 0,
- contentDescription);
+ StatusBarIcon icon = new StatusBarIcon(iconPackage, UserHandle.SYSTEM, iconId,
+ iconLevel, 0, contentDescription);
//Slog.d(TAG, "setIcon slot=" + slot + " index=" + index + " icon=" + icon);
mIcons.setIcon(index, icon);
diff --git a/services/core/java/com/android/server/telecom/TelecomLoaderService.java b/services/core/java/com/android/server/telecom/TelecomLoaderService.java
index f4bd61fa39cd..6c5452a3cb2e 100644
--- a/services/core/java/com/android/server/telecom/TelecomLoaderService.java
+++ b/services/core/java/com/android/server/telecom/TelecomLoaderService.java
@@ -188,7 +188,7 @@ public class TelecomLoaderService extends SystemService {
| Context.BIND_AUTO_CREATE;
// Bind to Telecom and register the service
- if (mContext.bindServiceAsUser(intent, serviceConnection, flags, UserHandle.OWNER)) {
+ if (mContext.bindServiceAsUser(intent, serviceConnection, flags, UserHandle.SYSTEM)) {
mServiceConnection = serviceConnection;
}
}
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index ee2353f1a1e8..d814ebf0351f 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -445,14 +445,16 @@ public final class TvInputManagerService extends SystemService {
// Unregister all callbacks and unbind all services.
for (ServiceState serviceState : userState.serviceStateMap.values()) {
- if (serviceState.callback != null) {
- try {
- serviceState.service.unregisterCallback(serviceState.callback);
- } catch (RemoteException e) {
- Slog.e(TAG, "error in unregisterCallback", e);
+ if (serviceState.service != null) {
+ if (serviceState.callback != null) {
+ try {
+ serviceState.service.unregisterCallback(serviceState.callback);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "error in unregisterCallback", e);
+ }
}
+ mContext.unbindService(serviceState.connection);
}
- mContext.unbindService(serviceState.connection);
}
userState.serviceStateMap.clear();
}
@@ -1974,7 +1976,12 @@ public final class TvInputManagerService extends SystemService {
Slog.d(TAG, "onServiceConnected(component=" + component + ")");
}
synchronized (mLock) {
- UserState userState = getOrCreateUserStateLocked(mUserId);
+ UserState userState = mUserStates.get(mUserId);
+ if (userState == null) {
+ // The user was removed while connecting.
+ mContext.unbindService(this);
+ return;
+ }
ServiceState serviceState = userState.serviceStateMap.get(mComponent);
serviceState.service = ITvInputService.Stub.asInterface(service);
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 192b168122bd..a64cda60ec1b 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -1003,17 +1003,33 @@ 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);
return set;
@@ -1056,7 +1072,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 +1098,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 67c9678eeb9e..5a1ed582358c 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -108,6 +108,9 @@ class AppWindowToken extends WindowToken {
boolean mLaunchTaskBehind;
boolean mEnteringAnimation;
+ // True if the windows associated with this token should be cropped to their stack bounds.
+ boolean mCropWindowsToStack;
+
// This application will have its window replaced due to relaunch. This allows window manager
// to differentiate between simple removal of a window and replacement. In the latter case it
// will preserve the old window until the new one is drawn.
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 325196d43056..ede377de0b14 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -16,12 +16,14 @@
package com.android.server.wm;
+import static android.app.ActivityManager.DOCKED_STACK_ID;
import static android.app.ActivityManager.HOME_STACK_ID;
import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY;
import static com.android.server.wm.WindowManagerService.TAG;
+import static com.android.server.wm.WindowState.RESIZE_HANDLE_WIDTH_IN_DP;
+import static com.android.server.wm.WindowState.BOUNDS_FOR_TOUCH;
-import android.content.res.Configuration;
import android.graphics.Rect;
import android.graphics.Region;
import android.util.DisplayMetrics;
@@ -72,6 +74,7 @@ class DisplayContent {
boolean mDisplayScalingDisabled;
private final DisplayInfo mDisplayInfo = new DisplayInfo();
private final Display mDisplay;
+ private final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
Rect mBaseDisplayRect = new Rect();
Rect mContentRect = new Rect();
@@ -82,11 +85,11 @@ class DisplayContent {
final boolean isDefaultDisplay;
/** Window tokens that are in the process of exiting, but still on screen for animations. */
- final ArrayList<WindowToken> mExitingTokens = new ArrayList<WindowToken>();
+ final ArrayList<WindowToken> mExitingTokens = new ArrayList<>();
/** Array containing all TaskStacks on this display. Array
* is stored in display order with the current bottom stack at 0. */
- private final ArrayList<TaskStack> mStacks = new ArrayList<TaskStack>();
+ private final ArrayList<TaskStack> mStacks = new ArrayList<>();
/** A special TaskStack with id==HOME_STACK_ID that moves to the bottom whenever any TaskStack
* (except a future lockscreen TaskStack) moves to the top. */
@@ -99,7 +102,8 @@ class DisplayContent {
Region mTouchExcludeRegion = new Region();
/** Save allocating when calculating rects */
- Rect mTmpRect = new Rect();
+ private Rect mTmpRect = new Rect();
+ private Rect mTmpRect2 = new Rect();
/** For gathering Task objects in order. */
final ArrayList<Task> mTmpTaskHistory = new ArrayList<Task>();
@@ -109,6 +113,8 @@ class DisplayContent {
/** Remove this display when animation on it has completed. */
boolean mDeferredRemoval;
+ final DockedStackDividerController mDividerControllerLocked;
+
/**
* @param display May not be null.
* @param service You know.
@@ -117,8 +123,10 @@ class DisplayContent {
mDisplay = display;
mDisplayId = display.getDisplayId();
display.getDisplayInfo(mDisplayInfo);
+ display.getMetrics(mDisplayMetrics);
isDefaultDisplay = mDisplayId == Display.DEFAULT_DISPLAY;
mService = service;
+ mDividerControllerLocked = new DockedStackDividerController(service.mContext, this);
}
int getDisplayId() {
@@ -137,6 +145,10 @@ class DisplayContent {
return mDisplayInfo;
}
+ DisplayMetrics getDisplayMetrics() {
+ return mDisplayMetrics;
+ }
+
/**
* Returns true if the specified UID has access to this display.
*/
@@ -174,6 +186,7 @@ class DisplayContent {
void updateDisplayInfo() {
mDisplay.getDisplayInfo(mDisplayInfo);
+ mDisplay.getMetrics(mDisplayMetrics);
for (int i = mStacks.size() - 1; i >= 0; --i) {
mStacks.get(i).updateDisplayInfo(null);
}
@@ -234,7 +247,7 @@ class DisplayContent {
for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
final Task task = tasks.get(taskNdx);
task.getBounds(mTmpRect);
- if (mTmpRect.contains(x, y)) {
+ if (task.inFreeformWorkspace() && mTmpRect.contains(x, y)) {
return task.mTaskId;
}
}
@@ -243,11 +256,11 @@ class DisplayContent {
}
/**
- * Find the id of the task whose outside touch area (for resizing) (x, y)
- * falls within. Returns -1 if the touch doesn't fall into a resizing area.
+ * Find the window whose outside touch area (for resizing) (x, y) falls within.
+ * Returns null if the touch doesn't fall into a resizing area.
*/
- int taskIdForControlPoint(int x, int y) {
- final int delta = calculatePixelFromDp(WindowState.RESIZE_HANDLE_WIDTH_IN_DP);
+ WindowState findWindowForControlPoint(int x, int y) {
+ final int delta = mService.dipToPixel(RESIZE_HANDLE_WIDTH_IN_DP, mDisplayMetrics);
for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
TaskStack stack = mStacks.get(stackNdx);
if (!stack.allowTaskResize()) {
@@ -257,38 +270,40 @@ class DisplayContent {
for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
final Task task = tasks.get(taskNdx);
if (task.isFullscreen()) {
- return -1;
+ return null;
}
- task.getBounds(mTmpRect);
- mTmpRect.inset(-delta, -delta);
- if (mTmpRect.contains(x, y)) {
- mTmpRect.inset(delta, delta);
- if (!mTmpRect.contains(x, y)) {
- return task.mTaskId;
+
+ // We need to use the visible frame on the window for any touch-related
+ // tests. Can't use the task's bounds because the original task bounds
+ // might be adjusted to fit the content frame. (One example is when the
+ // task is put to top-left quadrant, the actual visible frame would not
+ // start at (0,0) after it's adjusted for the status bar.)
+ WindowState win = task.getTopAppMainWindow();
+ if (win != null) {
+ win.getVisibleBounds(mTmpRect, !BOUNDS_FOR_TOUCH);
+ mTmpRect.inset(-delta, -delta);
+ if (mTmpRect.contains(x, y)) {
+ mTmpRect.inset(delta, delta);
+ if (!mTmpRect.contains(x, y)) {
+ return win;
+ }
+ // User touched inside the task. No need to look further,
+ // focus transfer will be handled in ACTION_UP.
+ return null;
}
- // User touched inside the task. No need to look further,
- // focus transfer will be handled in ACTION_UP.
- return -1;
}
}
}
- return -1;
- }
-
- private int calculatePixelFromDp(int dp) {
- final Configuration serviceConfig = mService.mCurConfiguration;
- // TODO(multidisplay): Update Dp to that of display stack is on.
- final float density = serviceConfig.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
- return (int)(dp * density);
+ return null;
}
void setTouchExcludeRegion(Task focusedTask) {
mTouchExcludeRegion.set(mBaseDisplayRect);
WindowList windows = getWindowList();
- final int delta = calculatePixelFromDp(WindowState.RESIZE_HANDLE_WIDTH_IN_DP);
+ final int delta = mService.dipToPixel(RESIZE_HANDLE_WIDTH_IN_DP, mDisplayMetrics);
for (int i = windows.size() - 1; i >= 0; --i) {
final WindowState win = windows.get(i);
- final Task task = win.mAppToken != null ? win.getTask() : null;
+ final Task task = win.getTask();
if (win.isVisibleLw() && task != null) {
/**
* Exclusion region is the region that TapDetector doesn't care about.
@@ -299,7 +314,7 @@ class DisplayContent {
* (For freeform focused task, the below logic will first remove the enlarged
* area, then add back the inner area.)
*/
- final boolean isFreeformed = win.inFreeformWorkspace();
+ final boolean isFreeformed = task.inFreeformWorkspace();
if (task != focusedTask || isFreeformed) {
mTmpRect.set(win.mVisibleFrame);
mTmpRect.intersect(win.mVisibleInsets);
@@ -442,6 +457,35 @@ class DisplayContent {
}
}
+ void rotateBounds(int oldRotation, int newRotation, Rect bounds) {
+ final int rotationDelta = DisplayContent.deltaRotation(oldRotation, newRotation);
+ getLogicalDisplayRect(mTmpRect);
+ switch (rotationDelta) {
+ case Surface.ROTATION_0:
+ mTmpRect2.set(bounds);
+ break;
+ case Surface.ROTATION_90:
+ mTmpRect2.top = mTmpRect.bottom - bounds.right;
+ mTmpRect2.left = bounds.top;
+ mTmpRect2.right = mTmpRect2.left + bounds.height();
+ mTmpRect2.bottom = mTmpRect2.top + bounds.width();
+ break;
+ case Surface.ROTATION_180:
+ mTmpRect2.top = mTmpRect.bottom - bounds.bottom;
+ mTmpRect2.left = mTmpRect.right - bounds.right;
+ mTmpRect2.right = mTmpRect2.left + bounds.width();
+ mTmpRect2.bottom = mTmpRect2.top + bounds.height();
+ break;
+ case Surface.ROTATION_270:
+ mTmpRect2.top = bounds.left;
+ mTmpRect2.left = mTmpRect.right - bounds.bottom;
+ mTmpRect2.right = mTmpRect2.left + bounds.height();
+ mTmpRect2.bottom = mTmpRect2.top + bounds.width();
+ break;
+ }
+ bounds.set(mTmpRect2);
+ }
+
static int deltaRotation(int oldRotation, int newRotation) {
int delta = newRotation - oldRotation;
if (delta < 0) delta += 4;
@@ -522,4 +566,14 @@ class DisplayContent {
public String toString() {
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;
+ }
}
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
new file mode 100644
index 000000000000..ad207d4b8939
--- /dev/null
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+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;
+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 android.content.Context;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
+
+/**
+ * Controls showing and hiding of a docked stack divider on the display.
+ */
+public class DockedStackDividerController {
+ 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();
+
+ DockedStackDividerController(Context context, DisplayContent displayContent) {
+ mContext = context;
+ mDisplayContent = displayContent;
+ mDividerWidth = context.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.docked_stack_divider_thickness);
+ }
+
+ private void addDivider() {
+ View view = LayoutInflater.from(mContext).inflate(
+ com.android.internal.R.layout.docked_stack_divider, null);
+ WindowManagerGlobal manager = WindowManagerGlobal.getInstance();
+ WindowManager.LayoutParams params = new WindowManager.LayoutParams(
+ mDividerWidth, MATCH_PARENT, TYPE_DOCK_DIVIDER,
+ FLAG_TOUCHABLE_WHEN_WAKING | FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL
+ | FLAG_WATCH_OUTSIDE_TOUCH | FLAG_SPLIT_TOUCH,
+ PixelFormat.OPAQUE);
+ params.setTitle(TAG);
+ manager.addView(view, params, mDisplayContent.getDisplay(), null);
+ mView = view;
+ }
+
+ private void removeDivider() {
+ WindowManagerGlobal manager = WindowManagerGlobal.getInstance();
+ manager.removeView(mView, true /* immediate */);
+ mView = null;
+ }
+
+ boolean hasDivider() {
+ return mView != null;
+ }
+
+ void update() {
+ TaskStack stack = mDisplayContent.getDockedStack();
+ if (stack != null && mView == null) {
+ addDivider();
+ } else if (stack == null && mView != null) {
+ removeDivider();
+ }
+ }
+
+ int getWidth() {
+ return mDividerWidth;
+ }
+
+
+ void positionDockedStackedDivider(Rect frame) {
+ TaskStack stack = mDisplayContent.getDockedStack();
+ 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
+ // divider was deferred to WM thread and hasn't happened yet.
+ return;
+ }
+ final @TaskStack.DockSide int side = stack.getDockSide();
+ stack.getBounds(mTmpRect);
+ switch (side) {
+ case TaskStack.DOCKED_LEFT:
+ frame.set(mTmpRect.right, frame.top, mTmpRect.right + frame.width(), frame.bottom);
+ break;
+ case TaskStack.DOCKED_TOP:
+ frame.set(frame.left, mTmpRect.bottom, mTmpRect.right,
+ mTmpRect.bottom + frame.height());
+ break;
+ case TaskStack.DOCKED_RIGHT:
+ frame.set(mTmpRect.left - frame.width(), frame.top, mTmpRect.left, frame.bottom);
+ break;
+ case TaskStack.DOCKED_BOTTOM:
+ frame.set(frame.left, mTmpRect.top - frame.height(), frame.right, mTmpRect.top);
+ break;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index 8f77176feb73..352168283229 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -27,6 +27,7 @@ import android.content.ClipDescription;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
+import android.os.Binder;
import android.os.IBinder;
import android.os.Message;
import android.os.Process;
@@ -34,6 +35,7 @@ import android.os.RemoteException;
import android.util.Slog;
import android.view.Display;
import android.view.DragEvent;
+import android.view.DropPermissionHolder;
import android.view.InputChannel;
import android.view.SurfaceControl;
import android.view.View;
@@ -50,6 +52,7 @@ class DragState {
SurfaceControl mSurfaceControl;
int mFlags;
IBinder mLocalWin;
+ int mUid;
ClipData mData;
ClipDescription mDataDescription;
boolean mDragResult;
@@ -74,6 +77,7 @@ class DragState {
mSurfaceControl = surface;
mFlags = flags;
mLocalWin = localWin;
+ mUid = Binder.getCallingUid();
mNotifiedWindows = new ArrayList<WindowState>();
}
@@ -225,7 +229,7 @@ class DragState {
if (mDragInProgress && newWin.isPotentialDragTarget()) {
DragEvent event = obtainDragEvent(newWin, DragEvent.ACTION_DRAG_STARTED,
- touchX, touchY, null, desc, null, false);
+ touchX, touchY, null, desc, null, null, false);
try {
newWin.mClient.dispatchDragEvent(event);
// track each window that we've notified that the drag is starting
@@ -265,7 +269,7 @@ class DragState {
Slog.d(WindowManagerService.TAG, "broadcasting DRAG_ENDED");
}
DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DRAG_ENDED,
- 0, 0, null, null, null, mDragResult);
+ 0, 0, null, null, null, null, mDragResult);
for (WindowState ws: mNotifiedWindows) {
try {
ws.mClient.dispatchDragEvent(evt);
@@ -331,7 +335,7 @@ class DragState {
}
// force DRAG_EXITED_EVENT if appropriate
DragEvent evt = obtainDragEvent(mTargetWindow, DragEvent.ACTION_DRAG_EXITED,
- x, y, null, null, null, false);
+ x, y, null, null, null, null, false);
mTargetWindow.mClient.dispatchDragEvent(evt);
if (myPid != mTargetWindow.mSession.mPid) {
evt.recycle();
@@ -342,7 +346,7 @@ class DragState {
Slog.d(WindowManagerService.TAG, "sending DRAG_LOCATION to " + touchedWin);
}
DragEvent evt = obtainDragEvent(touchedWin, DragEvent.ACTION_DRAG_LOCATION,
- x, y, null, null, null, false);
+ x, y, null, null, null, null, false);
touchedWin.mClient.dispatchDragEvent(evt);
if (myPid != touchedWin.mSession.mPid) {
evt.recycle();
@@ -354,11 +358,15 @@ class DragState {
mTargetWindow = touchedWin;
}
+ WindowState getDropTargetWinLw(float x, float y) {
+ return getTouchedWinAtPointLw(x, y);
+ }
+
// Tell the drop target about the data. Returns 'true' if we can immediately
// dispatch the global drag-ended message, 'false' if we need to wait for a
// result from the recipient.
- boolean notifyDropLw(float x, float y) {
- WindowState touchedWin = getTouchedWinAtPointLw(x, y);
+ boolean notifyDropLw(WindowState touchedWin, DropPermissionHolder dropPermissionHolder,
+ float x, float y) {
if (touchedWin == null) {
// "drop" outside a valid window -- no recipient to apply a
// timeout to, and we can send the drag-ended message immediately.
@@ -372,7 +380,7 @@ class DragState {
final int myPid = Process.myPid();
final IBinder token = touchedWin.mClient.asBinder();
DragEvent evt = obtainDragEvent(touchedWin, DragEvent.ACTION_DROP, x, y,
- null, null, mData, false);
+ null, null, mData, dropPermissionHolder, false);
try {
touchedWin.mClient.dispatchDragEvent(evt);
@@ -415,7 +423,7 @@ class DragState {
continue;
}
- child.getTaskBounds(mTmpRect, !BOUNDS_FOR_TOUCH);
+ child.getVisibleBounds(mTmpRect, !BOUNDS_FOR_TOUCH);
if (!mTmpRect.contains(x, y)) {
// outside of this window's activity stack == don't tell about drags
continue;
@@ -438,13 +446,16 @@ class DragState {
private static DragEvent obtainDragEvent(WindowState win, int action,
float x, float y, Object localState,
- ClipDescription description, ClipData data, boolean result) {
+ ClipDescription description, ClipData data,
+ DropPermissionHolder dropPermissionHolder,
+ boolean result) {
float winX = x - win.mFrame.left;
float winY = y - win.mFrame.top;
if (win.mEnforceSizeCompat) {
winX *= win.mGlobalScale;
winY *= win.mGlobalScale;
}
- return DragEvent.obtain(action, winX, winY, localState, description, data, result);
+ return DragEvent.obtain(action, winX, winY, localState, description, data,
+ dropPermissionHolder, result);
}
} \ No newline at end of file
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 9adcafcf7ef1..4244205aabf8 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -178,7 +178,7 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks {
if (modal && child.mAppToken != null) {
// Limit the outer touch to the activity stack region.
flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
- child.getTaskBounds(mTmpRect, BOUNDS_FOR_TOUCH);
+ child.getVisibleBounds(mTmpRect, BOUNDS_FOR_TOUCH);
inputWindowHandle.touchableRegion.set(mTmpRect);
} else {
// Not modal or full screen modal
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 666d902682a7..d1111f70346a 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.app.ActivityManager.DOCKED_STACK_ID;
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;
@@ -40,6 +41,13 @@ class Task implements DimLayer.DimLayerUser {
* when no window animation is driving it. */
private static final int DEFAULT_DIM_DURATION = 200;
+ // Return value from {@link setBounds} indicating no change was made to the Task bounds.
+ static final int BOUNDS_CHANGE_NONE = 0;
+ // Return value from {@link setBounds} indicating the position of the Task bounds changed.
+ static final int BOUNDS_CHANGE_POSITION = 1;
+ // Return value from {@link setBounds} indicating the size of the Task bounds changed.
+ static final int BOUNDS_CHANGE_SIZE = 1 << 1;
+
TaskStack mStack;
final AppTokenList mAppTokens = new AppTokenList();
final int mTaskId;
@@ -65,6 +73,9 @@ class Task implements DimLayer.DimLayerUser {
// For handling display rotations.
private Rect mTmpRect2 = new Rect();
+ // Whether the task is currently being drag-resized
+ private boolean mDragResizing;
+
// The particular window with FLAG_DIM_BEHIND set. If null, hide mDimLayer.
WindowStateAnimator mDimWinAnimator;
// Used to support {@link android.view.WindowManager.LayoutParams#FLAG_DIM_BEHIND}
@@ -165,7 +176,7 @@ class Task implements DimLayer.DimLayerUser {
}
/** Set the task bounds. Passing in null sets the bounds to fullscreen. */
- boolean setBounds(Rect bounds, Configuration config) {
+ int setBounds(Rect bounds, Configuration config) {
if (config == null) {
config = Configuration.EMPTY;
}
@@ -190,7 +201,7 @@ class Task implements DimLayer.DimLayerUser {
// ensure bounds are entirely within the display rect
if (!bounds.intersect(mTmpRect)) {
// Can't set bounds outside the containing display...Sorry!
- return false;
+ return BOUNDS_CHANGE_NONE;
}
}
mFullscreen = mTmpRect.equals(bounds);
@@ -199,16 +210,38 @@ class Task implements DimLayer.DimLayerUser {
if (bounds == null) {
// Can't set to fullscreen if we don't have a display to get bounds from...
- return false;
+ return BOUNDS_CHANGE_NONE;
}
if (mBounds.equals(bounds) && oldFullscreen == mFullscreen && mRotation == rotation) {
- return false;
+ return BOUNDS_CHANGE_NONE;
+ }
+
+ int boundsChange = BOUNDS_CHANGE_NONE;
+ if (mBounds.left != bounds.left || mBounds.right != bounds.right) {
+ boundsChange |= BOUNDS_CHANGE_POSITION;
+ }
+ if (mBounds.width() != bounds.width() || mBounds.height() != bounds.height()) {
+ boundsChange |= BOUNDS_CHANGE_SIZE;
}
mBounds.set(bounds);
mRotation = rotation;
updateDimLayer();
mOverrideConfig = mFullscreen ? Configuration.EMPTY : config;
+ return boundsChange;
+ }
+
+ boolean resizeLocked(Rect bounds, Configuration configuration, boolean forced) {
+ int boundsChanged = setBounds(bounds, configuration);
+ if (forced) {
+ boundsChanged |= BOUNDS_CHANGE_SIZE;
+ }
+ if (boundsChanged == BOUNDS_CHANGE_NONE) {
+ return false;
+ }
+ if ((boundsChanged & BOUNDS_CHANGE_SIZE) == BOUNDS_CHANGE_SIZE) {
+ resizeWindows();
+ }
return true;
}
@@ -216,6 +249,14 @@ class Task implements DimLayer.DimLayerUser {
out.set(mBounds);
}
+ void setDragResizing(boolean dragResizing) {
+ mDragResizing = dragResizing;
+ }
+
+ boolean isDragResizing() {
+ return mDragResizing;
+ }
+
void updateDisplayInfo(final DisplayContent displayContent) {
if (displayContent == null) {
return;
@@ -231,31 +272,8 @@ class Task implements DimLayer.DimLayerUser {
// Device rotation changed. We don't want the task to move around on the screen when
// this happens, so update the task bounds so it stays in the same place.
- final int rotationDelta = DisplayContent.deltaRotation(mRotation, newRotation);
- displayContent.getLogicalDisplayRect(mTmpRect);
- switch (rotationDelta) {
- case Surface.ROTATION_0:
- mTmpRect2.set(mBounds);
- break;
- case Surface.ROTATION_90:
- mTmpRect2.top = mTmpRect.bottom - mBounds.right;
- mTmpRect2.left = mBounds.top;
- mTmpRect2.right = mTmpRect2.left + mBounds.height();
- mTmpRect2.bottom = mTmpRect2.top + mBounds.width();
- break;
- case Surface.ROTATION_180:
- mTmpRect2.top = mTmpRect.bottom - mBounds.bottom;
- mTmpRect2.left = mTmpRect.right - mBounds.right;
- mTmpRect2.right = mTmpRect2.left + mBounds.width();
- mTmpRect2.bottom = mTmpRect2.top + mBounds.height();
- break;
- case Surface.ROTATION_270:
- mTmpRect2.top = mBounds.left;
- mTmpRect2.left = mTmpRect.right - mBounds.bottom;
- mTmpRect2.right = mTmpRect2.left + mBounds.height();
- mTmpRect2.bottom = mTmpRect2.top + mBounds.width();
- break;
- }
+ mTmpRect2.set(mBounds);
+ displayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
setBounds(mTmpRect2, mOverrideConfig);
}
@@ -411,6 +429,19 @@ class Task implements DimLayer.DimLayerUser {
return (tokensCount != 0) && mAppTokens.get(tokensCount - 1).showForAllUsers;
}
+ boolean inFreeformWorkspace() {
+ 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;
+ }
+
@Override
public boolean isFullscreen() {
return mFullscreen;
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index 71b83a5e32ea..df2e5e80b59b 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -16,13 +16,17 @@
package com.android.server.wm;
-import com.android.server.input.InputApplicationHandle;
-import com.android.server.input.InputWindowHandle;
-import com.android.server.wm.WindowManagerService.H;
+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.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 java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
+import static com.android.server.wm.WindowManagerService.SHOW_TRANSACTIONS;
+import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP;
+import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_WIDTH_IN_DP;
import android.annotation.IntDef;
import android.graphics.Point;
@@ -30,20 +34,34 @@ 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.util.TypedValue;
+import android.view.Choreographer;
import android.view.Display;
+import android.view.DisplayInfo;
import android.view.InputChannel;
import android.view.InputDevice;
import android.view.InputEvent;
-import android.view.InputEventReceiver;
+import android.view.BatchedInputEventReceiver;
import android.view.MotionEvent;
+import android.view.SurfaceControl;
import android.view.WindowManager;
-class TaskPositioner {
+import com.android.server.input.InputApplicationHandle;
+import com.android.server.input.InputWindowHandle;
+import com.android.server.wm.WindowManagerService.H;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+class TaskPositioner implements DimLayer.DimLayerUser {
private static final String TAG = "TaskPositioner";
+ // The margin the pointer position has to be within the side of the screen to be
+ // considered at the side of the screen.
+ private static final int SIDE_MARGIN_DIP = 100;
+
@IntDef(flag = true,
value = {
CTRL_NONE,
@@ -65,23 +83,33 @@ class TaskPositioner {
private WindowPositionerEventReceiver mInputEventReceiver;
private Display mDisplay;
private final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
-
- private int mTaskId;
+ private DimLayer mDimLayer;
+ @CtrlType
+ private int mCurrentDimSide;
+ private Rect mTmpRect = new Rect();
+ private int mSideMargin;
+ private int mMinVisibleWidth;
+ private int mMinVisibleHeight;
+
+ private Task mTask;
+ private boolean mResizing;
private final Rect mWindowOriginalBounds = new Rect();
private final Rect mWindowDragBounds = new Rect();
private float mStartDragX;
private float mStartDragY;
@CtrlType
private int mCtrlType = CTRL_NONE;
+ private boolean mDragEnded = false;
InputChannel mServerChannel;
InputChannel mClientChannel;
InputApplicationHandle mDragApplicationHandle;
InputWindowHandle mDragWindowHandle;
- private final class WindowPositionerEventReceiver extends InputEventReceiver {
- public WindowPositionerEventReceiver(InputChannel inputChannel, Looper looper) {
- super(inputChannel, looper);
+ private final class WindowPositionerEventReceiver extends BatchedInputEventReceiver {
+ public WindowPositionerEventReceiver(
+ InputChannel inputChannel, Looper looper, Choreographer choreographer) {
+ super(inputChannel, looper, choreographer);
}
@Override
@@ -94,7 +122,14 @@ class TaskPositioner {
boolean handled = false;
try {
- boolean endDrag = false;
+ if (mDragEnded) {
+ // The drag has ended but the clean-up message has not been processed by
+ // window manager. Drop events that occur after this until window manager
+ // has a chance to clean-up the input handle.
+ handled = true;
+ return;
+ }
+
final float newX = motionEvent.getRawX();
final float newY = motionEvent.getRawY();
@@ -110,29 +145,52 @@ class TaskPositioner {
Slog.w(TAG, "ACTION_MOVE @ {" + newX + ", " + newY + "}");
}
synchronized (mService.mWindowMap) {
- notifyMoveLocked(newX, newY);
+ mDragEnded = notifyMoveLocked(newX, newY);
}
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "wm.TaskPositioner.resizeTask");
try {
- mService.mActivityManager.resizeTask(mTaskId, mWindowDragBounds);
+ mService.mActivityManager.resizeTask(
+ mTask.mTaskId, mWindowDragBounds, RESIZE_MODE_USER);
} catch(RemoteException e) {}
+ Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
} break;
case MotionEvent.ACTION_UP: {
if (DEBUG_TASK_POSITIONING) {
Slog.w(TAG, "ACTION_UP @ {" + newX + ", " + newY + "}");
}
- endDrag = true;
+ mDragEnded = true;
} break;
case MotionEvent.ACTION_CANCEL: {
if (DEBUG_TASK_POSITIONING) {
Slog.w(TAG, "ACTION_CANCEL @ {" + newX + ", " + newY + "}");
}
- endDrag = true;
+ mDragEnded = true;
} break;
}
- if (endDrag) {
+ if (mDragEnded) {
+ synchronized (mService.mWindowMap) {
+ endDragLocked();
+ }
+ try {
+ if (mResizing) {
+ // 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);
+ }
+
+ if (mCurrentDimSide != CTRL_NONE) {
+ final int createMode = mCurrentDimSide == CTRL_LEFT
+ ? DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT
+ : DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT;
+ mService.mActivityManager.moveTaskToDockedStack(
+ mTask.mTaskId, createMode, true /*toTop*/);
+ }
+ } catch(RemoteException e) {}
+
// Post back to WM to handle clean-ups. We still need the input
// event handler for the last finishInputEvent()!
mService.mH.sendEmptyMessage(H.FINISH_TASK_POSITIONING);
@@ -170,8 +228,8 @@ class TaskPositioner {
mClientChannel = channels[1];
mService.mInputManager.registerInputChannel(mServerChannel, null);
- mInputEventReceiver = new WindowPositionerEventReceiver(mClientChannel,
- mService.mH.getLooper());
+ mInputEventReceiver = new WindowPositionerEventReceiver(
+ mClientChannel, mService.mH.getLooper(), mService.mChoreographer);
mDragApplicationHandle = new InputApplicationHandle(null);
mDragApplicationHandle.name = TAG;
@@ -213,6 +271,13 @@ class TaskPositioner {
Slog.d(TAG, "Pausing rotation during re-position");
}
mService.pauseRotationLocked();
+
+ mDimLayer = new DimLayer(mService, this, mDisplay.getDisplayId());
+ mSideMargin = mService.dipToPixel(SIDE_MARGIN_DIP, mDisplayMetrics);
+ mMinVisibleWidth = mService.dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, mDisplayMetrics);
+ mMinVisibleHeight = mService.dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, mDisplayMetrics);
+
+ mDragEnded = false;
}
void unregister() {
@@ -238,6 +303,13 @@ class TaskPositioner {
mDragApplicationHandle = null;
mDisplay = null;
+ if (mDimLayer != null) {
+ mDimLayer.destroySurface();
+ mDimLayer = null;
+ }
+ mCurrentDimSide = CTRL_NONE;
+ mDragEnded = true;
+
// Resume rotations after a drag.
if (WindowManagerService.DEBUG_ORIENTATION) {
Slog.d(TAG, "Resuming rotation after re-position");
@@ -246,8 +318,8 @@ class TaskPositioner {
}
void startDragLocked(WindowState win, boolean resize, float startX, float startY) {
- if (DEBUG_TASK_POSITIONING) {Slog.d(TAG,
- "startDragLocked: win=" + win + ", resize=" + resize
+ if (DEBUG_TASK_POSITIONING) {
+ Slog.d(TAG, "startDragLocked: win=" + win + ", resize=" + resize
+ ", {" + startX + ", " + startY + "}");
}
mCtrlType = CTRL_NONE;
@@ -265,17 +337,23 @@ class TaskPositioner {
if (startY > visibleFrame.bottom) {
mCtrlType |= CTRL_BOTTOM;
}
+ mResizing = true;
}
- final Task task = win.getTask();
- mTaskId = task.mTaskId;
+ mTask = win.getTask();
mStartDragX = startX;
mStartDragY = startY;
- mService.getTaskBounds(mTaskId, mWindowOriginalBounds);
+ mService.getTaskBounds(mTask.mTaskId, mWindowOriginalBounds);
+ }
+
+ private void endDragLocked() {
+ mResizing = false;
+ mTask.setDragResizing(false);
}
- private void notifyMoveLocked(float x, float y) {
+ /** Returns true if the move operation should be ended. */
+ private boolean notifyMoveLocked(float x, float y) {
if (DEBUG_TASK_POSITIONING) {
Slog.d(TAG, "notifyMoveLw: {" + x + "," + y + "}");
}
@@ -284,33 +362,104 @@ class TaskPositioner {
// This is a resizing operation.
final int deltaX = Math.round(x - mStartDragX);
final int deltaY = Math.round(y - mStartDragY);
- // TODO: fix the min sizes when we have mininum width/height support,
- // use hard-coded min sizes for now.
- final int minSizeX = (int)(dipToPx(96));
- final int minSizeY = (int)(dipToPx(64));
int left = mWindowOriginalBounds.left;
int top = mWindowOriginalBounds.top;
int right = mWindowOriginalBounds.right;
int bottom = mWindowOriginalBounds.bottom;
if ((mCtrlType & CTRL_LEFT) != 0) {
- left = Math.min(left + deltaX, right - minSizeX);
+ left = Math.min(left + deltaX, right - mMinVisibleWidth);
}
if ((mCtrlType & CTRL_TOP) != 0) {
- top = Math.min(top + deltaY, bottom - minSizeY);
+ top = Math.min(top + deltaY, bottom - mMinVisibleHeight);
}
if ((mCtrlType & CTRL_RIGHT) != 0) {
- right = Math.max(left + minSizeX, right + deltaX);
+ right = Math.max(left + mMinVisibleWidth, right + deltaX);
}
if ((mCtrlType & CTRL_BOTTOM) != 0) {
- bottom = Math.max(top + minSizeY, bottom + deltaY);
+ bottom = Math.max(top + mMinVisibleHeight, bottom + deltaY);
}
mWindowDragBounds.set(left, top, right, bottom);
+ mTask.setDragResizing(true);
+ return false;
+ }
+
+ // This is a moving operation.
+ mTask.mStack.getBounds(mTmpRect);
+ mTmpRect.inset(mMinVisibleWidth, mMinVisibleHeight);
+ if (!mTmpRect.contains((int) x, (int) y)) {
+ // We end the moving operation if position is outside the stack bounds.
+ return true;
+ }
+ mWindowDragBounds.set(mWindowOriginalBounds);
+ mWindowDragBounds.offset(Math.round(x - mStartDragX), Math.round(y - mStartDragY));
+ updateDimLayerVisibility((int) x);
+ return false;
+ }
+
+ private void updateDimLayerVisibility(int x) {
+ @CtrlType
+ int dimSide = getDimSide(x);
+ if (dimSide == mCurrentDimSide) {
+ return;
+ }
+
+ mCurrentDimSide = dimSide;
+
+ if (SHOW_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION updateDimLayerVisibility");
+ SurfaceControl.openTransaction();
+ if (mCurrentDimSide == CTRL_NONE) {
+ mDimLayer.hide();
} else {
- // This is a moving operation.
- mWindowDragBounds.set(mWindowOriginalBounds);
- mWindowDragBounds.offset(Math.round(x - mStartDragX),
- Math.round(y - mStartDragY));
+ showDimLayer();
+ }
+ SurfaceControl.closeTransaction();
+ }
+
+ /**
+ * Returns the side of the screen the dim layer should be shown.
+ * @param x horizontal coordinate used to determine if the dim layer should be shown
+ * @return Returns {@link #CTRL_LEFT} if the dim layer should be shown on the left half of the
+ * screen, {@link #CTRL_RIGHT} if on the right side, or {@link #CTRL_NONE} if the dim layer
+ * shouldn't be shown.
+ */
+ private int getDimSide(int x) {
+ if (mTask.mStack.mStackId != FREEFORM_WORKSPACE_STACK_ID
+ || !mTask.mStack.isFullscreen()
+ || mService.mCurConfiguration.orientation != ORIENTATION_LANDSCAPE) {
+ return CTRL_NONE;
}
+
+ mTask.mStack.getBounds(mTmpRect);
+ if (x - mSideMargin <= mTmpRect.left) {
+ return CTRL_LEFT;
+ }
+ if (x + mSideMargin >= mTmpRect.right) {
+ return CTRL_RIGHT;
+ }
+
+ return CTRL_NONE;
+ }
+
+ private void showDimLayer() {
+ mTask.mStack.getBounds(mTmpRect);
+ if (mCurrentDimSide == CTRL_LEFT) {
+ mTmpRect.right = mTmpRect.centerX();
+ } else if (mCurrentDimSide == CTRL_RIGHT) {
+ mTmpRect.left = mTmpRect.centerX();
+ }
+
+ mDimLayer.setBounds(mTmpRect);
+ mDimLayer.show(getDragLayerLocked(), 0.5f, 0);
+ }
+
+ @Override /** {@link DimLayer.DimLayerUser} */
+ public boolean isFullscreen() {
+ return false;
+ }
+
+ @Override /** {@link DimLayer.DimLayerUser} */
+ public DisplayInfo getDisplayInfo() {
+ return mTask.mStack.getDisplayInfo();
}
private int getDragLayerLocked() {
@@ -318,8 +467,4 @@ class TaskPositioner {
* WindowManagerService.TYPE_LAYER_MULTIPLIER
+ WindowManagerService.TYPE_LAYER_OFFSET;
}
-
- private float dipToPx(float dip) {
- return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, mDisplayMetrics);
- }
-} \ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index ae3bb9b20b04..3357a9cb208e 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -20,6 +20,7 @@ import static android.app.ActivityManager.*;
import static com.android.server.wm.WindowManagerService.DEBUG_TASK_MOVEMENT;
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;
@@ -29,9 +30,12 @@ import android.util.Slog;
import android.util.SparseArray;
import android.view.DisplayInfo;
+import android.view.Surface;
import com.android.server.EventLogTags;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
public class TaskStack implements DimLayer.DimLayerUser {
@@ -54,6 +58,7 @@ public class TaskStack implements DimLayer.DimLayerUser {
/** For comparison with DisplayContent bounds. */
private Rect mTmpRect = new Rect();
+ private Rect TmpRect2 = new Rect();
/** Content limits relative to the DisplayContent this sits in. */
private Rect mBounds = new Rect();
@@ -61,6 +66,9 @@ public class TaskStack implements DimLayer.DimLayerUser {
/** Whether mBounds is fullscreen */
private boolean mFullscreen = true;
+ // Device rotation as of the last time {@link #mBounds} was set.
+ int mRotation;
+
/** Support for non-zero {@link android.view.animation.Animation#getBackgroundColor()} */
DimLayer mAnimationBackgroundSurface;
@@ -73,6 +81,20 @@ public class TaskStack implements DimLayer.DimLayerUser {
/** Detach this stack from its display when animation completes. */
boolean mDeferDetach;
+ static final int DOCKED_INVALID = -1;
+ static final int DOCKED_LEFT = 1;
+ static final int DOCKED_TOP = 2;
+ static final int DOCKED_RIGHT = 3;
+ static final int DOCKED_BOTTOM = 4;
+ @IntDef({
+ DOCKED_INVALID,
+ DOCKED_LEFT,
+ DOCKED_TOP,
+ DOCKED_RIGHT,
+ DOCKED_BOTTOM})
+ @Retention(RetentionPolicy.SOURCE)
+ @interface DockSide {}
+
TaskStack(WindowManagerService service, int stackId) {
mService = service;
mStackId = stackId;
@@ -101,30 +123,22 @@ public class TaskStack implements DimLayer.DimLayerUser {
/**
* Set the bounds of the stack and its containing tasks.
* @param stackBounds New stack bounds. Passing in null sets the bounds to fullscreen.
- * @param resizeTasks If true, the tasks within the stack will also be resized.
* @param configs Configuration for individual tasks, keyed by task id.
* @param taskBounds Bounds for individual tasks, keyed by task id.
* @return True if the stack bounds was changed.
* */
- boolean setBounds(Rect stackBounds, boolean resizeTasks, SparseArray<Configuration> configs,
- SparseArray<Rect> taskBounds) {
+ boolean setBounds(
+ Rect stackBounds, SparseArray<Configuration> configs, SparseArray<Rect> taskBounds) {
if (!setBounds(stackBounds)) {
return false;
}
- if (!resizeTasks) {
- return true;
- }
-
// Update bounds of containing tasks.
for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
final Task task = mTasks.get(taskNdx);
Configuration config = configs.get(task.mTaskId);
if (config != null) {
Rect bounds = taskBounds.get(task.mTaskId);
- if (bounds == null) {
- bounds = stackBounds;
- }
task.setBounds(bounds, config);
} else {
Slog.wtf(TAG, "No config for task: " + task + ", is there a mismatch with AM?");
@@ -135,8 +149,10 @@ public class TaskStack implements DimLayer.DimLayerUser {
private boolean setBounds(Rect bounds) {
boolean oldFullscreen = mFullscreen;
+ int rotation = Surface.ROTATION_0;
if (mDisplayContent != null) {
mDisplayContent.getLogicalDisplayRect(mTmpRect);
+ rotation = mDisplayContent.getDisplayInfo().rotation;
if (bounds == null) {
bounds = mTmpRect;
mFullscreen = true;
@@ -154,12 +170,13 @@ public class TaskStack implements DimLayer.DimLayerUser {
// Can't set to fullscreen if we don't have a display to get bounds from...
return false;
}
- if (mBounds.equals(bounds) && oldFullscreen == mFullscreen) {
+ if (mBounds.equals(bounds) && oldFullscreen == mFullscreen && mRotation == rotation) {
return false;
}
mAnimationBackgroundSurface.setBounds(bounds);
mBounds.set(bounds);
+ mRotation = rotation;
return true;
}
@@ -171,8 +188,13 @@ public class TaskStack implements DimLayer.DimLayerUser {
if (mDisplayContent != null) {
if (bounds != null) {
setBounds(bounds);
+ } else if (mFullscreen) {
+ setBounds(null);
} else {
- setBounds(mFullscreen ? null : mBounds);
+ TmpRect2.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);
@@ -330,7 +352,8 @@ public class TaskStack implements DimLayer.DimLayerUser {
// the docked stack occupies a dedicated region on screen.
bounds = new Rect();
displayContent.getLogicalDisplayRect(mTmpRect);
- getInitialDockedStackBounds(mTmpRect, bounds, mStackId);
+ getInitialDockedStackBounds(mTmpRect, bounds, mStackId,
+ mDisplayContent.mDividerControllerLocked.getWidth() / 2);
}
updateDisplayInfo(bounds);
@@ -349,25 +372,29 @@ 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 adjustment
*/
- private static void getInitialDockedStackBounds(
- Rect displayRect, Rect outBounds, int stackId) {
+ private static void getInitialDockedStackBounds(Rect displayRect, Rect outBounds, int stackId,
+ int adjustment) {
// Docked stack start off occupying half the screen space.
- // TODO(multi-window): Need to support the selecting which half of the screen the
- // docked stack uses for snapping windows to the edge of the screen.
+ 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 (stackId == DOCKED_STACK_ID) {
+ if (placeTopOrLeft) {
if (splitHorizontally) {
- outBounds.right = displayRect.centerX();
+ outBounds.right = displayRect.centerX() - adjustment;
} else {
- outBounds.bottom = displayRect.centerY();
+ outBounds.bottom = displayRect.centerY() - adjustment;
}
} else {
if (splitHorizontally) {
- outBounds.left = displayRect.centerX();
+ outBounds.left = displayRect.centerX() + adjustment;
} else {
- outBounds.top = displayRect.centerY();
+ outBounds.top = displayRect.centerY() + adjustment;
}
}
}
@@ -380,7 +407,8 @@ public class TaskStack implements DimLayer.DimLayerUser {
private void resizeNonDockedStacks(boolean fullscreen) {
mDisplayContent.getLogicalDisplayRect(mTmpRect);
if (!fullscreen) {
- getInitialDockedStackBounds(mTmpRect, mTmpRect, FULLSCREEN_WORKSPACE_STACK_ID);
+ getInitialDockedStackBounds(mTmpRect, mTmpRect, FULLSCREEN_WORKSPACE_STACK_ID,
+ mDisplayContent.mDividerControllerLocked.getWidth());
}
final int count = mService.mStackIdToStack.size();
@@ -410,8 +438,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;
}
}
@@ -506,4 +533,36 @@ public class TaskStack implements DimLayer.DimLayerUser {
public String toString() {
return "{stackId=" + mStackId + " tasks=" + mTasks + "}";
}
+
+ /**
+ * For docked workspace provides information which side of the screen was the dock anchored.
+ */
+ @DockSide
+ int getDockSide() {
+ if (mStackId != DOCKED_STACK_ID) {
+ return DOCKED_INVALID;
+ }
+ if (mDisplayContent == null) {
+ return DOCKED_INVALID;
+ }
+ mDisplayContent.getLogicalDisplayRect(mTmpRect);
+ final int orientation = mService.mCurConfiguration.orientation;
+ if (orientation == Configuration.ORIENTATION_PORTRAIT) {
+ // Portrait mode, docked either at the top or the bottom.
+ if (mBounds.top - mTmpRect.top < mTmpRect.bottom - mBounds.bottom) {
+ return DOCKED_TOP;
+ } else {
+ return DOCKED_BOTTOM;
+ }
+ } else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
+ // Landscape mode, docked either on the left or on the right.
+ if (mBounds.left - mTmpRect.left < mTmpRect.right - mBounds.right) {
+ return DOCKED_LEFT;
+ } else {
+ return DOCKED_RIGHT;
+ }
+ } else {
+ return DOCKED_INVALID;
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index fc23fd1b2f9f..1a946b2c5d17 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -736,7 +736,8 @@ class WallpaperController {
insertionIndex = windows.indexOf(wallpaperTarget);
}
}
- if (DEBUG_WALLPAPER_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG,
+ if (DEBUG_WALLPAPER_LIGHT || DEBUG_WINDOW_MOVEMENT
+ || (DEBUG_ADD_REMOVE && oldIndex != insertionIndex)) Slog.v(TAG,
"Moving wallpaper " + wallpaper
+ " from " + oldIndex + " to " + insertionIndex);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 82030ddc0506..76e7c3c84575 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -16,6 +16,36 @@
package com.android.server.wm;
+import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
+import static android.app.ActivityManager.DOCKED_STACK_ID;
+import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
+import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
+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.LAST_APPLICATION_WINDOW;
+import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
+import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
+import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
+import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
+import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
+import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+
+import static com.android.server.wm.WindowState.BOUNDS_FOR_TOUCH;
+
import android.Manifest;
import android.animation.ValueAnimator;
import android.app.ActivityManagerNative;
@@ -79,6 +109,7 @@ import android.view.AppTransitionAnimationSpec;
import android.view.Choreographer;
import android.view.Display;
import android.view.DisplayInfo;
+import android.view.DropPermissionHolder;
import android.view.Gravity;
import android.view.IApplicationToken;
import android.view.IInputFilter;
@@ -110,9 +141,7 @@ import android.view.WindowManagerPolicy;
import android.view.WindowManagerPolicy.PointerEventListener;
import android.view.animation.Animation;
-import static com.android.server.wm.WindowState.BOUNDS_FOR_TOUCH;
import com.android.internal.app.IAssistScreenshotReceiver;
-import com.android.internal.app.IBatteryStats;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.view.IInputContext;
import com.android.internal.view.IInputMethodClient;
@@ -149,31 +178,6 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
-import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
-import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
-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.LAST_APPLICATION_WINDOW;
-import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
-import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
-import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
-import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
-import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
-import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
-import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
-import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
-import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION;
-import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
-import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
-import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
-import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
-
/** {@hide} */
public class WindowManagerService extends IWindowManager.Stub
implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
@@ -458,6 +462,8 @@ public class WindowManagerService extends IWindowManager.Stub
private boolean mKeyguardWaitingForActivityDrawn;
+ static int sDockedStackCreateMode = DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
+
class RotationWatcher {
IRotationWatcher watcher;
IBinder.DeathRecipient deathRecipient;
@@ -623,6 +629,13 @@ public class WindowManagerService extends IWindowManager.Stub
private WindowContentFrameStats mTempWindowRenderStats;
+ private static final int DRAG_FLAGS_URI_ACCESS = View.DRAG_FLAG_GLOBAL_URI_READ |
+ View.DRAG_FLAG_GLOBAL_URI_WRITE;
+
+ private static final int DRAG_FLAGS_URI_PERMISSIONS = DRAG_FLAGS_URI_ACCESS |
+ View.DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION |
+ View.DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION;
+
final class DragInputEventReceiver extends InputEventReceiver {
// Set, if stylus button was down at the start of the drag.
private boolean mStylusButtonDownAtStart;
@@ -668,7 +681,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (DEBUG_DRAG) Slog.d(TAG, "Button no longer pressed; dropping at "
+ newX + "," + newY);
synchronized (mWindowMap) {
- endDrag = mDragState.notifyDropLw(newX, newY);
+ endDrag = completeDrop(newX, newY);
}
} else {
synchronized (mWindowMap) {
@@ -682,7 +695,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (DEBUG_DRAG) Slog.d(TAG, "Got UP on move channel; dropping at "
+ newX + "," + newY);
synchronized (mWindowMap) {
- endDrag = mDragState.notifyDropLw(newX, newY);
+ endDrag = completeDrop(newX, newY);
}
} break;
@@ -712,6 +725,25 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
+ private boolean completeDrop(float x, float y) {
+ WindowState dropTargetWin = mDragState.getDropTargetWinLw(x, y);
+
+ DropPermissionHolder dropPermissionHolder = null;
+ if ((mDragState.mFlags & View.DRAG_FLAG_GLOBAL) != 0 &&
+ (mDragState.mFlags & DRAG_FLAGS_URI_ACCESS) != 0) {
+ dropPermissionHolder = new DropPermissionHolder(
+ mDragState.mData,
+ mActivityManager,
+ mDragState.mUid,
+ dropTargetWin.getOwningPackage(),
+ mDragState.mFlags & DRAG_FLAGS_URI_PERMISSIONS,
+ UserHandle.getUserId(mDragState.mUid),
+ UserHandle.getUserId(dropTargetWin.getOwningUid()));
+ }
+
+ return mDragState.notifyDropLw(dropTargetWin, dropPermissionHolder, x, y);
+ }
+
/**
* Whether the UI is currently running in touch mode (not showing
* navigational focus because the user is directly pressing the screen).
@@ -891,6 +923,7 @@ public class WindowManagerService extends IWindowManager.Stub
mAllowTheaterModeWakeFromLayout = context.getResources().getBoolean(
com.android.internal.R.bool.config_allowTheaterModeWakeFromWindowLayout);
+
LocalServices.addService(WindowManagerInternal.class, new LocalService());
initPolicy();
@@ -904,7 +937,6 @@ public class WindowManagerService extends IWindowManager.Stub
SurfaceControl.closeTransaction();
}
- updateCircularDisplayMaskIfNeeded();
showEmulatorDisplayOverlayIfNeeded();
}
@@ -1825,6 +1857,11 @@ public class WindowManagerService extends IWindowManager.Stub
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
+ } else if (type == TYPE_DOCK_DIVIDER) {
+ if (displayContent.mDividerControllerLocked.hasDivider()) {
+ Slog.w(TAG, "Attempted to add docked stack divider twice. Aborting.");
+ return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
+ }
} else if (token.appWindowToken != null) {
Slog.w(TAG, "Non-null appWindowToken for system window of type=" + type);
// It is not valid to use an app token with other system types; we will
@@ -2169,7 +2206,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;
@@ -2410,6 +2447,7 @@ public class WindowManagerService extends IWindowManager.Stub
boolean inTouchMode;
boolean configChanged;
boolean surfaceChanged = false;
+ boolean dragResizing = false;
boolean animating;
boolean hasStatusBarPermission =
mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
@@ -2558,6 +2596,23 @@ public class WindowManagerService extends IWindowManager.Stub
surfaceChanged = true;
}
}
+
+ // If we're starting a drag-resize, we'll be changing the surface size as well as
+ // notifying the client to render to with an offset from the surface's top-left.
+ // Do a screen freeze, and keep the old surface until the the first frame drawn to
+ // the new surface comes back, so that we avoid a flash due to mismatching surface
+ // setups on window manager side and client side.
+ if (win.isDragResizeChanged()) {
+ win.setDragResizing();
+ if (win.mHasSurface) {
+ winAnimator.mDestroyPendingSurfaceUponRedraw = true;
+ winAnimator.mSurfaceDestroyDeferred = true;
+ winAnimator.destroySurfaceLocked();
+ startFreezingDisplayLocked(false, 0, 0);
+ toBeDisplayed = true;
+ }
+ }
+ dragResizing = win.isDragResizing();
try {
if (!win.mHasSurface) {
surfaceChanged = true;
@@ -2724,7 +2779,8 @@ public class WindowManagerService extends IWindowManager.Stub
return (inTouchMode ? WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE : 0)
| (toBeDisplayed ? WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME : 0)
- | (surfaceChanged ? WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED : 0);
+ | (surfaceChanged ? WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED : 0)
+ | (dragResizing ? WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING : 0);
}
public void performDeferredDestroyWindow(Session session, IWindow client) {
@@ -3056,7 +3112,7 @@ public class WindowManagerService extends IWindowManager.Stub
public void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int userId,
int configChanges, boolean voiceInteraction, boolean launchTaskBehind,
- Rect taskBounds, Configuration config) {
+ Rect taskBounds, Configuration config, boolean cropWindowsToStack) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"addAppToken()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
@@ -3090,6 +3146,7 @@ public class WindowManagerService extends IWindowManager.Stub
atoken.layoutConfigChanges = (configChanges &
(ActivityInfo.CONFIG_SCREEN_SIZE | ActivityInfo.CONFIG_ORIENTATION)) != 0;
atoken.mLaunchTaskBehind = launchTaskBehind;
+ atoken.mCropWindowsToStack = cropWindowsToStack;
if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG, "addAppToken: " + atoken
+ " to stack=" + stackId + " task=" + taskId + " at " + addPos);
@@ -3625,12 +3682,8 @@ public class WindowManagerService extends IWindowManager.Stub
// pretend like we didn't see that.
return;
}
- final boolean windowIsTranslucentDefined = ent.array.hasValue(
- com.android.internal.R.styleable.Window_windowIsTranslucent);
final boolean windowIsTranslucent = ent.array.getBoolean(
com.android.internal.R.styleable.Window_windowIsTranslucent, false);
- final boolean windowSwipeToDismiss = ent.array.getBoolean(
- com.android.internal.R.styleable.Window_windowSwipeToDismiss, false);
final boolean windowIsFloating = ent.array.getBoolean(
com.android.internal.R.styleable.Window_windowIsFloating, false);
final boolean windowShowWallpaper = ent.array.getBoolean(
@@ -3640,7 +3693,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Translucent=" + windowIsTranslucent
+ " Floating=" + windowIsFloating
+ " ShowWallpaper=" + windowShowWallpaper);
- if (windowIsTranslucent || (!windowIsTranslucentDefined && windowSwipeToDismiss)) {
+ if (windowIsTranslucent) {
return;
}
if (windowIsFloating || windowDisableStarting) {
@@ -4426,6 +4479,12 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
+ public void setDockedStackCreateMode(int mode) {
+ synchronized (mWindowMap) {
+ sDockedStackCreateMode = mode;
+ }
+ }
+
/**
* Create a new TaskStack and place it on a DisplayContent.
* @param stackId The unique identifier of the new stack.
@@ -4448,7 +4507,10 @@ 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) {
@@ -4471,6 +4533,11 @@ 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) {
@@ -4559,12 +4626,11 @@ public class WindowManagerService extends IWindowManager.Stub
* Re-sizes a stack and its containing tasks.
* @param stackId Id of stack to resize.
* @param bounds New stack bounds. Passing in null sets the bounds to fullscreen.
- * @param resizeTasks If true, the tasks within the stack will also be resized.
* @param configs Configurations for tasks in the resized stack, keyed by task id.
* @param taskBounds Bounds for tasks in the resized stack, keyed by task id.
* @return True if the stack is now fullscreen.
* */
- public boolean resizeStack(int stackId, Rect bounds, boolean resizeTasks,
+ public boolean resizeStack(int stackId, Rect bounds,
SparseArray<Configuration> configs, SparseArray<Rect> taskBounds) {
synchronized (mWindowMap) {
final TaskStack stack = mStackIdToStack.get(stackId);
@@ -4572,7 +4638,7 @@ public class WindowManagerService extends IWindowManager.Stub
throw new IllegalArgumentException("resizeStack: stackId " + stackId
+ " not found.");
}
- if (stack.setBounds(bounds, resizeTasks, configs, taskBounds)) {
+ if (stack.setBounds(bounds, configs, taskBounds)) {
stack.resizeWindows();
stack.getDisplayContent().layoutNeeded = true;
mWindowPlacerLocked.performSurfacePlacement();
@@ -4609,19 +4675,18 @@ public class WindowManagerService extends IWindowManager.Stub
* Returns a {@link Configuration} object that contains configurations settings
* that should be overridden due to the operation.
*/
- public void resizeTask(int taskId, Rect bounds, Configuration configuration, boolean relayout) {
+ public void resizeTask(int taskId, Rect bounds, Configuration configuration,
+ boolean relayout, boolean forced) {
synchronized (mWindowMap) {
Task task = mTaskIdToTask.get(taskId);
if (task == null) {
throw new IllegalArgumentException("resizeTask: taskId " + taskId
+ " not found.");
}
- if (task.setBounds(bounds, configuration)) {
- task.resizeWindows();
- if (relayout) {
- task.getDisplayContent().layoutNeeded = true;
- mWindowPlacerLocked.performSurfacePlacement();
- }
+
+ if (task.resizeLocked(bounds, configuration, forced) && relayout) {
+ task.getDisplayContent().layoutNeeded = true;
+ mWindowPlacerLocked.performSurfacePlacement();
}
}
}
@@ -5272,7 +5337,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
- public void updateCircularDisplayMaskIfNeeded() {
+ private void updateCircularDisplayMaskIfNeeded() {
// we're fullscreen and not hosted in an ActivityView
if (mContext.getResources().getConfiguration().isScreenRound()
&& mContext.getResources().getBoolean(
@@ -5600,7 +5665,7 @@ public class WindowManagerService extends IWindowManager.Stub
int right = wf.right - cr.right;
int bottom = wf.bottom - cr.bottom;
frame.union(left, top, right, bottom);
- ws.getTaskBounds(stackBounds, !BOUNDS_FOR_TOUCH);
+ ws.getVisibleBounds(stackBounds, !BOUNDS_FOR_TOUCH);
if (!frame.intersect(stackBounds)) {
// Set frame empty if there's no intersection.
frame.setEmpty();
@@ -6798,37 +6863,29 @@ public class WindowManagerService extends IWindowManager.Stub
}
boolean startMovingTask(IWindow window, float startX, float startY) {
- WindowState callingWin = null;
+ WindowState win = null;
synchronized (mWindowMap) {
- callingWin = windowForClientLocked(null, window, false);
- if (!startPositioningLocked(callingWin, false /*resize*/, startX, startY)) {
+ win = windowForClientLocked(null, window, false);
+ if (!startPositioningLocked(win, false /*resize*/, startX, startY)) {
return false;
}
}
try {
- mActivityManager.setFocusedTask(callingWin.getTask().mTaskId);
+ mActivityManager.setFocusedTask(win.getTask().mTaskId);
} catch(RemoteException e) {}
return true;
}
private void startResizingTask(DisplayContent displayContent, int startX, int startY) {
- int taskId = -1;
- AppWindowToken atoken = null;
+ WindowState win = null;
synchronized (mWindowMap) {
- taskId = displayContent.taskIdForControlPoint(startX, startY);
- Task task = mTaskIdToTask.get(taskId);
- if (task == null || task.mAppTokens == null) {
- return;
- }
- AppTokenList tokens = task.mAppTokens;
- atoken = tokens.get(tokens.size() - 1);
- WindowState win = atoken.findMainWindow();
+ win = displayContent.findWindowForControlPoint(startX, startY);
if (!startPositioningLocked(win, true /*resize*/, startX, startY)) {
return;
}
}
try {
- mActivityManager.setFocusedTask(taskId);
+ mActivityManager.setFocusedTask(win.getTask().mTaskId);
} catch(RemoteException e) {}
}
@@ -7064,6 +7121,8 @@ public class WindowManagerService extends IWindowManager.Stub
mActivityManager.updateConfiguration(null);
} catch (RemoteException e) {
}
+
+ updateCircularDisplayMaskIfNeeded();
}
private void displayReady(int displayId) {
@@ -7147,6 +7206,8 @@ public class WindowManagerService extends IWindowManager.Stub
public static final int TAP_DOWN_OUTSIDE_TASK = 40;
public static final int FINISH_TASK_POSITIONING = 41;
+ public static final int UPDATE_DOCKED_STACK_DIVIDER = 42;
+
@Override
public void handleMessage(Message msg) {
if (DEBUG_WINDOW_TRACE) {
@@ -7686,6 +7747,13 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
break;
+ case UPDATE_DOCKED_STACK_DIVIDER: {
+ DisplayContent content = (DisplayContent) msg.obj;
+ synchronized (mWindowMap) {
+ content.mDividerControllerLocked.update();
+ }
+ }
+ break;
}
if (DEBUG_WINDOW_TRACE) {
Slog.v(TAG, "handleMessage: exit");
@@ -8227,7 +8295,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);
@@ -8402,15 +8470,18 @@ public class WindowManagerService extends IWindowManager.Stub
Slog.v(TAG, "Win " + w + " config changed: "
+ mCurConfiguration);
}
+ final boolean dragResizingChanged = w.isDragResizeChanged();
if (localLOGV) Slog.v(TAG, "Resizing " + w
+ ": configChanged=" + configChanged
+ + " dragResizingChanged=" + dragResizingChanged
+ " last=" + w.mLastFrame + " frame=" + w.mFrame);
w.mLastFrame.set(w.mFrame);
if (w.mContentInsetsChanged
|| w.mVisibleInsetsChanged
|| winAnimator.mSurfaceResized
|| w.mOutsetsChanged
- || configChanged) {
+ || configChanged
+ || dragResizingChanged) {
if (DEBUG_RESIZE || DEBUG_ORIENTATION) {
Slog.v(TAG, "Resize reasons for w=" + w + ": "
+ " contentInsetsChanged=" + w.mContentInsetsChanged
@@ -8422,7 +8493,8 @@ public class WindowManagerService extends IWindowManager.Stub
+ " outsetsChanged=" + w.mOutsetsChanged
+ " " + w.mOutsets.toShortString()
+ " surfaceResized=" + winAnimator.mSurfaceResized
- + " configChanged=" + configChanged);
+ + " configChanged=" + configChanged
+ + " dragResizingChanged=" + dragResizingChanged);
}
w.mLastOverscanInsets.set(w.mOverscanInsets);
@@ -8431,12 +8503,12 @@ public class WindowManagerService extends IWindowManager.Stub
w.mLastStableInsets.set(w.mStableInsets);
w.mLastOutsets.set(w.mOutsets);
makeWindowFreezingScreenIfNeededLocked(w);
- // If the orientation is changing, then we need to
- // hold off on unfreezing the display until this
- // window has been redrawn; to do that, we need
- // to go through the process of getting informed
- // by the application when it has finished drawing.
- if (w.mOrientationChanging) {
+ // If the orientation is changing, or we're starting or ending
+ // a drag resizing action, then we need to hold off on unfreezing
+ // the display until this window has been redrawn; to do that,
+ // we need to go through the process of getting informed by the
+ // application when it has finished drawing.
+ if (w.mOrientationChanging || dragResizingChanged) {
if (DEBUG_SURFACE_TRACE || DEBUG_ANIM || DEBUG_ORIENTATION) Slog.v(TAG,
"Orientation start waiting for draw mDrawState=DRAW_PENDING in "
+ w + ", surface " + winAnimator.mSurfaceControl);
@@ -9815,6 +9887,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);
@@ -9827,6 +9905,10 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
+ static int dipToPixel(int dip, DisplayMetrics displayMetrics) {
+ return (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, displayMetrics);
+ }
+
private final class LocalService extends WindowManagerInternal {
@Override
public void requestTraversalFromDisplayManager() {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 789354db1739..37deffe39bea 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -16,7 +16,7 @@
package com.android.server.wm;
-import static android.app.ActivityManager.FREEFORM_WORKSPACE_STACK_ID;
+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;
@@ -24,6 +24,7 @@ import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
+import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
@@ -38,6 +39,7 @@ 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;
@@ -81,12 +83,14 @@ final class WindowState implements WindowManagerPolicy.WindowState {
static final String TAG = "WindowState";
// The minimal size of a window within the usable area of the freeform stack.
- private static final int MINIMUM_VISIBLE_WIDTH_IN_DP = 48;
- private static final int MINIMUM_VISIBLE_HEIGHT_IN_DP = 32;
+ // TODO(multi-window): fix the min sizes when we have mininum width/height support,
+ // use hard-coded min sizes for now.
+ static final int MINIMUM_VISIBLE_WIDTH_IN_DP = 48;
+ static final int MINIMUM_VISIBLE_HEIGHT_IN_DP = 32;
// The thickness of a window resize handle outside the window bounds on the free form workspace
// to capture touch events in that area.
- static final int RESIZE_HANDLE_WIDTH_IN_DP = 10;
+ static final int RESIZE_HANDLE_WIDTH_IN_DP = 30;
static final boolean BOUNDS_FOR_TOUCH = true;
@@ -126,6 +130,8 @@ final class WindowState implements WindowManagerPolicy.WindowState {
boolean mAppFreezing;
boolean mAttachedHidden; // is our parent window hidden?
boolean mWallpaperVisible; // for wallpaper, what was last vis report?
+ boolean mDragResizing;
+ boolean mDragResizeChanging;
RemoteCallbackList<IWindowFocusObserver> mFocusCallbacks;
@@ -379,6 +385,8 @@ final class WindowState implements WindowManagerPolicy.WindowState {
*/
PowerManager.WakeLock mDrawLock;
+ final private Rect mTmpRect = new Rect();
+
WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
WindowState attachedWindow, int appOp, int seq, WindowManager.LayoutParams a,
int viewVisibility, final DisplayContent displayContent) {
@@ -555,9 +563,9 @@ final class WindowState implements WindowManagerPolicy.WindowState {
}
mHaveFrame = true;
- final Task task = mAppToken != null ? getTask() : null;
+ final Task task = getTask();
final boolean nonFullscreenTask = task != null && !task.isFullscreen();
- final boolean freeformWorkspace = inFreeformWorkspace();
+ final boolean freeformWorkspace = task != null && task.inFreeformWorkspace();
if (nonFullscreenTask) {
task.getBounds(mContainingFrame);
final WindowState imeWin = mService.mInputMethodWindow;
@@ -689,8 +697,11 @@ final class WindowState implements WindowManagerPolicy.WindowState {
// into a usable area..
final int height = Math.min(mFrame.height(), mContentFrame.height());
final int width = Math.min(mContentFrame.width(), mFrame.width());
- final int minVisibleHeight = calculatePixelFromDp(MINIMUM_VISIBLE_HEIGHT_IN_DP);
- final int minVisibleWidth = calculatePixelFromDp(MINIMUM_VISIBLE_WIDTH_IN_DP);
+ final DisplayMetrics displayMetrics = getDisplayContent().getDisplayMetrics();
+ final int minVisibleHeight =
+ mService.dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, displayMetrics);
+ final int minVisibleWidth =
+ mService.dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, displayMetrics);
final int top = Math.max(mContentFrame.top,
Math.min(mFrame.top, mContentFrame.bottom - minVisibleHeight));
final int left = Math.max(mContentFrame.left + minVisibleWidth - width,
@@ -699,6 +710,8 @@ final class WindowState implements WindowManagerPolicy.WindowState {
mContentFrame.set(mFrame);
mVisibleFrame.set(mContentFrame);
mStableFrame.set(mContentFrame);
+ } else if (mAttrs.type == TYPE_DOCK_DIVIDER) {
+ mDisplayContent.mDividerControllerLocked.positionDockedStackedDivider(mFrame);
} else {
mContentFrame.set(Math.max(mContentFrame.left, mFrame.left),
Math.max(mContentFrame.top, mFrame.top),
@@ -897,6 +910,11 @@ final class WindowState implements WindowManagerPolicy.WindowState {
return stack == null ? mDisplayContent : stack.getDisplayContent();
}
+ public DisplayInfo getDisplayInfo() {
+ final DisplayContent displayContent = getDisplayContent();
+ return displayContent != null ? displayContent.getDisplayInfo() : null;
+ }
+
public int getDisplayId() {
final DisplayContent displayContent = getDisplayContent();
if (displayContent == null) {
@@ -906,12 +924,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
}
Task getTask() {
- AppWindowToken wtoken = mAppToken == null ? mService.mFocusedApp : mAppToken;
- if (wtoken == null) {
- return null;
- }
- final Task task = wtoken.mTask;
- return task;
+ return mAppToken != null ? mAppToken.mTask : null;
}
TaskStack getStack() {
@@ -921,28 +934,45 @@ final class WindowState implements WindowManagerPolicy.WindowState {
return task.mStack;
}
}
- return mDisplayContent.getHomeStack();
+ return null;
}
/**
- * Retrieves the bounds for a task.
+ * Retrieves the visible bounds of the window.
* @param bounds The rect which gets the bounds.
* @param forTouch Pass in BOUNDS_FOR_TOUCH to get touch related bounds, otherwise visible
* bounds will be returned.
*/
- void getTaskBounds(Rect bounds, boolean forTouch) {
- final Task task = getTask();
- if (task != null) {
- task.getBounds(bounds);
- if (forTouch == BOUNDS_FOR_TOUCH) {
- if (inFreeformWorkspace()) {
- final int delta = calculatePixelFromDp(RESIZE_HANDLE_WIDTH_IN_DP);
- bounds.inset(-delta, -delta);
- }
+ void getVisibleBounds(Rect bounds, boolean forTouch) {
+ boolean intersectWithStackBounds = mAppToken != null && mAppToken.mCropWindowsToStack;
+ bounds.setEmpty();
+ mTmpRect.setEmpty();
+ if (intersectWithStackBounds) {
+ final TaskStack stack = getStack();
+ if (stack != null) {
+ stack.getBounds(mTmpRect);
+ } else {
+ intersectWithStackBounds = false;
+ }
+ }
+
+ bounds.set(mVisibleFrame);
+ if (intersectWithStackBounds) {
+ bounds.intersect(mTmpRect);
+ }
+
+ if (bounds.isEmpty()) {
+ bounds.set(mFrame);
+ if (intersectWithStackBounds) {
+ bounds.intersect(mTmpRect);
}
return;
}
- bounds.set(mFrame);
+ if (forTouch && inFreeformWorkspace()) {
+ final DisplayMetrics displayMetrics = getDisplayContent().getDisplayMetrics();
+ final int delta = mService.dipToPixel(RESIZE_HANDLE_WIDTH_IN_DP, displayMetrics);
+ bounds.inset(-delta, -delta);
+ }
}
public long getInputDispatchingTimeoutNanos() {
@@ -1437,10 +1467,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);
@@ -1577,6 +1604,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);
@@ -1642,6 +1670,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) {
@@ -1669,15 +1698,21 @@ final class WindowState implements WindowManagerPolicy.WindowState {
boolean inFreeformWorkspace() {
final Task task = getTask();
- return task != null && task.mStack != null &&
- task.mStack.mStackId == FREEFORM_WORKSPACE_STACK_ID;
+ return task != null && task.inFreeformWorkspace();
}
- private int calculatePixelFromDp(int dp) {
- final Configuration serviceConfig = mService.mCurConfiguration;
- // TODO(multidisplay): Update Dp to that of display stack is on.
- final float density = serviceConfig.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
- return (int)(dp * density);
+ boolean isDragResizeChanged() {
+ final Task task = getTask();
+ return task != null && mDragResizing != task.isDragResizing();
+ }
+
+ void setDragResizing() {
+ final Task task = getTask();
+ mDragResizing = task != null && task.isDragResizing();
+ }
+
+ boolean isDragResizing() {
+ return mDragResizing;
}
void dump(PrintWriter pw, String prefix, boolean dumpAll) {
@@ -1867,15 +1902,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 bf1ab8fab7d0..0b9f2c634db8 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -107,6 +107,7 @@ class WindowStateAnimator {
*/
boolean mSurfaceDestroyDeferred;
+ boolean mDestroyPendingSurfaceUponRedraw;
float mShownAlpha = 0;
float mAlpha = 0;
float mLastAlpha = 0;
@@ -115,6 +116,7 @@ class WindowStateAnimator {
Rect mClipRect = new Rect();
Rect mTmpClipRect = new Rect();
Rect mLastClipRect = new Rect();
+ Rect mTmpStackBounds = new Rect();
// Used to save animation distances between the time they are calculated and when they are
// used.
@@ -168,6 +170,11 @@ class WindowStateAnimator {
/** Set when the window has been shown in the screen the first time. */
static final int HAS_DRAWN = 4;
+ // Surface flinger doesn't support crop rectangles where width or height is non-positive.
+ // However, we need to somehow handle the situation where the cropping would completely hide
+ // the window. We achieve this by explicitly hiding the surface and not letting it be shown.
+ private boolean mHiddenForCrop;
+
String drawStateToString() {
switch (mDrawState) {
case NO_SURFACE: return "NO_SURFACE";
@@ -540,9 +547,15 @@ class WindowStateAnimator {
Slog.i(TAG, "commitFinishDrawingLocked: mDrawState=READY_TO_SHOW " + mSurfaceControl);
}
mDrawState = READY_TO_SHOW;
+ boolean result = false;
final AppWindowToken atoken = mWin.mAppToken;
if (atoken == null || atoken.allDrawn || mWin.mAttrs.type == TYPE_APPLICATION_STARTING) {
- return performShowLocked();
+ result = performShowLocked();
+ }
+ if (mDestroyPendingSurfaceUponRedraw) {
+ mDestroyPendingSurfaceUponRedraw = false;
+ destroyDeferredSurfaceLocked();
+ mService.stopFreezingDisplayLocked();
}
return false;
}
@@ -790,6 +803,9 @@ class WindowStateAnimator {
flags |= SurfaceControl.SECURE;
}
+ float left = w.mFrame.left + w.mXOffset;
+ float top = w.mFrame.top + w.mYOffset;
+
int width;
int height;
if ((attrs.flags & LayoutParams.FLAG_SCALED) != 0) {
@@ -798,8 +814,19 @@ class WindowStateAnimator {
width = w.mRequestedWidth;
height = w.mRequestedHeight;
} else {
- width = w.mCompatFrame.width();
- height = w.mCompatFrame.height();
+ // When we're doing a drag-resizing, request a surface that's fullscreen size,
+ // so that we don't need to reallocate during the process. This also prevents
+ // buffer drops due to size mismatch.
+ final DisplayInfo displayInfo = w.getDisplayInfo();
+ if (displayInfo != null && w.isDragResizing()) {
+ left = 0;
+ top = 0;
+ width = displayInfo.logicalWidth;
+ height = displayInfo.logicalHeight;
+ } else {
+ width = w.mCompatFrame.width();
+ height = w.mCompatFrame.height();
+ }
}
// Something is wrong and SurfaceFlinger will not like this,
@@ -811,9 +838,6 @@ class WindowStateAnimator {
height = 1;
}
- float left = w.mFrame.left + w.mXOffset;
- float top = w.mFrame.top + w.mYOffset;
-
// Adjust for surface insets.
width += attrs.surfaceInsets.left + attrs.surfaceInsets.right;
height += attrs.surfaceInsets.top + attrs.surfaceInsets.bottom;
@@ -1063,6 +1087,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
@@ -1141,7 +1167,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)
@@ -1187,6 +1212,13 @@ class WindowStateAnimator {
return;
} else if (mIsWallpaper && mService.mWindowPlacerLocked.mWallpaperActionPending) {
return;
+ } else if (mWin.isDragResizeChanged()) {
+ // This window is awaiting a relayout because user just started (or ended)
+ // drag-resizing. The shown frame (which affects surface size and pos)
+ // should not be updated until we get next finished draw with the new surface.
+ // Otherwise one or two frames rendered with old settings would be displayed
+ // with new geometry.
+ return;
}
if (WindowManagerService.localLOGV) Slog.v(
@@ -1309,9 +1341,15 @@ class WindowStateAnimator {
final boolean fullscreen = w.isFullscreen(displayInfo.appWidth, displayInfo.appHeight);
final Rect clipRect = mTmpClipRect;
- // We use the clip rect as provided by the tranformation for non-fullscreen windows to
- // avoid premature clipping with the system decor rect.
- clipRect.set((mHasClipRect && !fullscreen) ? mClipRect : w.mSystemDecorRect);
+ if (w.isDragResizing()) {
+ // When we're doing a drag-resizing, the surface is set up to cover full screen.
+ // Set the clip rect to be the same size so that we don't get any scaling.
+ clipRect.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
+ } else {
+ // We use the clip rect as provided by the tranformation for non-fullscreen windows to
+ // avoid premature clipping with the system decor rect.
+ clipRect.set((mHasClipRect && !fullscreen) ? mClipRect : w.mSystemDecorRect);
+ }
// Expand the clip rect for surface insets.
final WindowManager.LayoutParams attrs = w.mAttrs;
@@ -1331,12 +1369,25 @@ class WindowStateAnimator {
// so we need to translate to match the actual surface coordinates.
clipRect.offset(attrs.surfaceInsets.left, attrs.surfaceInsets.top);
+ // 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);
try {
if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
"CROP " + clipRect.toShortString(), null);
- mSurfaceControl.setWindowCrop(clipRect);
+ if (clipRect.width() > 0 && clipRect.height() > 0) {
+ mSurfaceControl.setWindowCrop(clipRect);
+ mHiddenForCrop = false;
+ } else {
+ hide();
+ mHiddenForCrop = true;
+ }
} catch (RuntimeException e) {
Slog.w(TAG, "Error setting crop surface of " + w
+ " crop=" + clipRect.toShortString(), e);
@@ -1347,9 +1398,32 @@ class WindowStateAnimator {
}
}
+ private void adjustCropToStackBounds(WindowState w, Rect clipRect) {
+ final AppWindowToken appToken = w.mAppToken;
+ if (appToken != null && appToken.mCropWindowsToStack) {
+ TaskStack stack = w.getTask().mStack;
+ stack.getBounds(mTmpStackBounds);
+ final int surfaceX = (int) mSurfaceX;
+ final int surfaceY = (int) mSurfaceY;
+ // We need to do some acrobatics with surface position, because their clip region is
+ // relative to the inside of the surface, but the stack bounds aren't.
+ clipRect.left = Math.max(0,
+ Math.max(mTmpStackBounds.left, surfaceX + clipRect.left) - surfaceX);
+ clipRect.top = Math.max(0,
+ Math.max(mTmpStackBounds.top, surfaceY + clipRect.top) - surfaceY);
+ clipRect.right = Math.max(0,
+ Math.min(mTmpStackBounds.right, surfaceX + clipRect.right) - surfaceX);
+ clipRect.bottom = Math.max(0,
+ Math.min(mTmpStackBounds.bottom, surfaceY + clipRect.bottom) - surfaceY);
+ }
+ }
+
void setSurfaceBoundariesLocked(final boolean recoveringMemory) {
final WindowState w = mWin;
+ float left = w.mShownFrame.left;
+ float top = w.mShownFrame.top;
+
int width;
int height;
if ((w.mAttrs.flags & LayoutParams.FLAG_SCALED) != 0) {
@@ -1358,8 +1432,19 @@ class WindowStateAnimator {
width = w.mRequestedWidth;
height = w.mRequestedHeight;
} else {
- width = w.mCompatFrame.width();
- height = w.mCompatFrame.height();
+ // When we're doing a drag-resizing, request a surface that's fullscreen size,
+ // so that we don't need to reallocate during the process. This also prevents
+ // buffer drops due to size mismatch.
+ final DisplayInfo displayInfo = w.getDisplayInfo();
+ if (displayInfo != null && w.isDragResizing()) {
+ left = 0;
+ top = 0;
+ width = displayInfo.logicalWidth;
+ height = displayInfo.logicalHeight;
+ } else {
+ width = w.mCompatFrame.width();
+ height = w.mCompatFrame.height();
+ }
}
// Something is wrong and SurfaceFlinger will not like this,
@@ -1371,9 +1456,6 @@ class WindowStateAnimator {
height = 1;
}
- float left = w.mShownFrame.left;
- float top = w.mShownFrame.top;
-
// Adjust for surface insets.
final LayoutParams attrs = w.getAttrs();
final int displayId = w.getDisplayId();
@@ -1517,7 +1599,7 @@ class WindowStateAnimator {
mDsDx * w.mHScale, mDtDx * w.mVScale,
mDsDy * w.mHScale, mDtDy * w.mVScale);
- if (mLastHidden && mDrawState == HAS_DRAWN) {
+ if (mLastHidden && mDrawState == HAS_DRAWN && !mHiddenForCrop) {
if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
"SHOW (performLayout)", null);
if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG, "Showing " + w
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 52efa6803499..d86a8afe1499 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;
@@ -625,8 +626,11 @@ class WindowSurfacePlacer {
for (int i = windows.size() - 1; i >= 0; i--) {
WindowState w = windows.get(i);
- final Task task = w.getTask();
- if (task == null && w.getAttrs().type != TYPE_PRIVATE_PRESENTATION) {
+ Task task = w.getTask();
+ if (task == null && w.getDisplayContent().getHomeStack() == null
+ && w.getAttrs().type != TYPE_PRIVATE_PRESENTATION) {
+ // TODO: Understand what the use case is here and see if the conditions can be
+ // simplified.
continue;
}
@@ -712,7 +716,12 @@ class WindowSurfacePlacer {
}
}
}
-
+ /*
+ * Updates the shown frame before we set up the surface. This is needed because
+ * the resizing could change the top-left position (in addition to size) of the
+ * window. setSurfaceBoundariesLocked uses mShownFrame to position the surface.
+ */
+ winAnimator.computeShownFrameLocked();
winAnimator.setSurfaceBoundariesLocked(recoveringMemory);
}
@@ -1220,11 +1229,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)
@@ -1243,15 +1256,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/core/jni/com_android_server_AlarmManagerService.cpp b/services/core/jni/com_android_server_AlarmManagerService.cpp
index 3fd0f84f5957..5cbb277a2f12 100644
--- a/services/core/jni/com_android_server_AlarmManagerService.cpp
+++ b/services/core/jni/com_android_server_AlarmManagerService.cpp
@@ -460,7 +460,7 @@ static jint android_server_AlarmManagerService_waitForAlarm(JNIEnv*, jobject, jl
return result;
}
-static JNINativeMethod sMethods[] = {
+static const JNINativeMethod sMethods[] = {
/* name, signature, funcPtr */
{"init", "()J", (void*)android_server_AlarmManagerService_init},
{"close", "(J)V", (void*)android_server_AlarmManagerService_close},
diff --git a/services/core/jni/com_android_server_AssetAtlasService.cpp b/services/core/jni/com_android_server_AssetAtlasService.cpp
index 8f4fb51093d9..ed79ceb3a9d3 100644
--- a/services/core/jni/com_android_server_AssetAtlasService.cpp
+++ b/services/core/jni/com_android_server_AssetAtlasService.cpp
@@ -204,7 +204,7 @@ static jboolean com_android_server_AssetAtlasService_upload(JNIEnv* env, jobject
const char* const kClassPathName = "com/android/server/AssetAtlasService";
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
{ "nUploadAtlas", "(Landroid/view/GraphicBuffer;Landroid/graphics/Bitmap;)Z",
(void*) com_android_server_AssetAtlasService_upload },
};
diff --git a/services/core/jni/com_android_server_ConsumerIrService.cpp b/services/core/jni/com_android_server_ConsumerIrService.cpp
index f5121cdf5580..7104870349b5 100644
--- a/services/core/jni/com_android_server_ConsumerIrService.cpp
+++ b/services/core/jni/com_android_server_ConsumerIrService.cpp
@@ -100,7 +100,7 @@ static jintArray halGetCarrierFrequencies(JNIEnv *env, jobject /* obj */,
return freqsOut.getJavaArray();
}
-static JNINativeMethod method_table[] = {
+static const JNINativeMethod method_table[] = {
{ "halOpen", "()J", (void *)halOpen },
{ "halTransmit", "(JI[I)I", (void *)halTransmit },
{ "halGetCarrierFrequencies", "(J)[I", (void *)halGetCarrierFrequencies},
diff --git a/services/core/jni/com_android_server_PersistentDataBlockService.cpp b/services/core/jni/com_android_server_PersistentDataBlockService.cpp
index 4ccfa56cd30c..06de592d7533 100644
--- a/services/core/jni/com_android_server_PersistentDataBlockService.cpp
+++ b/services/core/jni/com_android_server_PersistentDataBlockService.cpp
@@ -97,7 +97,7 @@ namespace android {
return wipe_block_device(fd);
}
- static JNINativeMethod sMethods[] = {
+ static const JNINativeMethod sMethods[] = {
/* name, signature, funcPtr */
{"nativeGetBlockDeviceSize", "(Ljava/lang/String;)J", (void*)com_android_server_PersistentDataBlockService_getBlockDeviceSize},
{"nativeWipe", "(Ljava/lang/String;)I", (void*)com_android_server_PersistentDataBlockService_wipe},
diff --git a/services/core/jni/com_android_server_SerialService.cpp b/services/core/jni/com_android_server_SerialService.cpp
index d48d159b1178..1bd7a599ed60 100644
--- a/services/core/jni/com_android_server_SerialService.cpp
+++ b/services/core/jni/com_android_server_SerialService.cpp
@@ -55,7 +55,7 @@ static jobject android_server_SerialService_open(JNIEnv *env, jobject /* thiz */
}
-static JNINativeMethod method_table[] = {
+static const JNINativeMethod method_table[] = {
{ "native_open", "(Ljava/lang/String;)Landroid/os/ParcelFileDescriptor;",
(void*)android_server_SerialService_open },
};
diff --git a/services/core/jni/com_android_server_SystemServer.cpp b/services/core/jni/com_android_server_SystemServer.cpp
index 64514a9f72e8..c7d6b95083d2 100644
--- a/services/core/jni/com_android_server_SystemServer.cpp
+++ b/services/core/jni/com_android_server_SystemServer.cpp
@@ -37,7 +37,7 @@ static void android_server_SystemServer_startSensorService(JNIEnv* /* env */, jo
/*
* JNI registration.
*/
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
{ "startSensorService", "()V", (void*) android_server_SystemServer_startSensorService },
};
diff --git a/services/core/jni/com_android_server_UsbDeviceManager.cpp b/services/core/jni/com_android_server_UsbDeviceManager.cpp
index a1bff9d850bf..3733a55e7504 100644
--- a/services/core/jni/com_android_server_UsbDeviceManager.cpp
+++ b/services/core/jni/com_android_server_UsbDeviceManager.cpp
@@ -118,7 +118,7 @@ static jint android_server_UsbDeviceManager_getAudioMode(JNIEnv* /* env */, jobj
return result;
}
-static JNINativeMethod method_table[] = {
+static const JNINativeMethod method_table[] = {
{ "nativeGetAccessoryStrings", "()[Ljava/lang/String;",
(void*)android_server_UsbDeviceManager_getAccessoryStrings },
{ "nativeOpenAccessory", "()Landroid/os/ParcelFileDescriptor;",
diff --git a/services/core/jni/com_android_server_UsbHostManager.cpp b/services/core/jni/com_android_server_UsbHostManager.cpp
index d8c172fd51cc..795f6aa6018a 100644
--- a/services/core/jni/com_android_server_UsbHostManager.cpp
+++ b/services/core/jni/com_android_server_UsbHostManager.cpp
@@ -186,7 +186,7 @@ static jobject android_server_UsbHostManager_openDevice(JNIEnv *env, jobject /*
gParcelFileDescriptorOffsets.mConstructor, fileDescriptor);
}
-static JNINativeMethod method_table[] = {
+static const JNINativeMethod method_table[] = {
{ "monitorUsbHostBus", "()V", (void*)android_server_UsbHostManager_monitorUsbHostBus },
{ "nativeOpenDevice", "(Ljava/lang/String;)Landroid/os/ParcelFileDescriptor;",
(void*)android_server_UsbHostManager_openDevice },
diff --git a/services/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp
index fb1166b41d41..64278ed4499b 100644
--- a/services/core/jni/com_android_server_VibratorService.cpp
+++ b/services/core/jni/com_android_server_VibratorService.cpp
@@ -46,7 +46,7 @@ static void vibratorOff(JNIEnv* /* env */, jobject /* clazz */)
vibrator_off();
}
-static JNINativeMethod method_table[] = {
+static const JNINativeMethod method_table[] = {
{ "vibratorExists", "()Z", (void*)vibratorExists },
{ "vibratorOn", "(J)V", (void*)vibratorOn },
{ "vibratorOff", "()V", (void*)vibratorOff }
diff --git a/services/core/jni/com_android_server_am_ActivityManagerService.cpp b/services/core/jni/com_android_server_am_ActivityManagerService.cpp
index 52217b955852..50e4502a9a3a 100644
--- a/services/core/jni/com_android_server_am_ActivityManagerService.cpp
+++ b/services/core/jni/com_android_server_am_ActivityManagerService.cpp
@@ -110,7 +110,6 @@ namespace android
return 0;
}
char buf[17];
- char *curBuf = buf;
while (fgets(buf, 16, boost_cpuset_file)) {
//ALOGE("Appending FD %s to fg", buf);
int i = 0;
diff --git a/services/core/jni/com_android_server_am_BatteryStatsService.cpp b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
index dfc5ef6ec366..5c4365979644 100644
--- a/services/core/jni/com_android_server_am_BatteryStatsService.cpp
+++ b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
@@ -170,7 +170,7 @@ static jint nativeWaitWakeup(JNIEnv *env, jobject clazz, jobject outBuf)
return mergedreasonpos - mergedreason;
}
-static JNINativeMethod method_table[] = {
+static const JNINativeMethod method_table[] = {
{ "nativeWaitWakeup", "(Ljava/nio/ByteBuffer;)I", (void*)nativeWaitWakeup },
};
diff --git a/services/core/jni/com_android_server_connectivity_Vpn.cpp b/services/core/jni/com_android_server_connectivity_Vpn.cpp
index 7faeb49d7b56..2d0dfd2f7f26 100644
--- a/services/core/jni/com_android_server_connectivity_Vpn.cpp
+++ b/services/core/jni/com_android_server_connectivity_Vpn.cpp
@@ -350,7 +350,7 @@ static bool delAddress(JNIEnv *env, jobject thiz, jstring jName, jstring jAddres
//------------------------------------------------------------------------------
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
{"jniCreate", "(I)I", (void *)create},
{"jniGetName", "(I)Ljava/lang/String;", (void *)getName},
{"jniSetAddresses", "(Ljava/lang/String;Ljava/lang/String;)I", (void *)setAddresses},
diff --git a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
index f2d0f060c66c..b72cf4dc94d0 100644
--- a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
+++ b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
@@ -384,7 +384,7 @@ static jboolean nativeIsConnected(JNIEnv* env, jclass clazz, jlong controllerPtr
return controller->isConnected(port) ? JNI_TRUE : JNI_FALSE ;
}
-static JNINativeMethod sMethods[] = {
+static const JNINativeMethod sMethods[] = {
/* name, signature, funcPtr */
{ "nativeInit",
"(Lcom/android/server/hdmi/HdmiCecController;Landroid/os/MessageQueue;)J",
diff --git a/services/core/jni/com_android_server_input_InputApplicationHandle.cpp b/services/core/jni/com_android_server_input_InputApplicationHandle.cpp
index 11388d80a9d2..bdc109d086f6 100644
--- a/services/core/jni/com_android_server_input_InputApplicationHandle.cpp
+++ b/services/core/jni/com_android_server_input_InputApplicationHandle.cpp
@@ -120,7 +120,7 @@ static void android_server_InputApplicationHandle_nativeDispose(JNIEnv* env, job
}
-static JNINativeMethod gInputApplicationHandleMethods[] = {
+static const JNINativeMethod gInputApplicationHandleMethods[] = {
/* name, signature, funcPtr */
{ "nativeDispose", "()V",
(void*) android_server_InputApplicationHandle_nativeDispose },
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index e29d0a94610c..1d4f047ff605 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -1369,7 +1369,7 @@ static void nativeMonitor(JNIEnv* /* env */, jclass /* clazz */, jlong ptr) {
// ----------------------------------------------------------------------------
-static JNINativeMethod gInputManagerMethods[] = {
+static const JNINativeMethod gInputManagerMethods[] = {
/* name, signature, funcPtr */
{ "nativeInit",
"(Lcom/android/server/input/InputManagerService;Landroid/content/Context;Landroid/os/MessageQueue;)J",
diff --git a/services/core/jni/com_android_server_input_InputWindowHandle.cpp b/services/core/jni/com_android_server_input_InputWindowHandle.cpp
index 01c51cf6cfe0..92ef7f1ae096 100644
--- a/services/core/jni/com_android_server_input_InputWindowHandle.cpp
+++ b/services/core/jni/com_android_server_input_InputWindowHandle.cpp
@@ -210,7 +210,7 @@ static void android_server_InputWindowHandle_nativeDispose(JNIEnv* env, jobject
}
-static JNINativeMethod gInputWindowHandleMethods[] = {
+static const JNINativeMethod gInputWindowHandleMethods[] = {
/* name, signature, funcPtr */
{ "nativeDispose", "()V",
(void*) android_server_InputWindowHandle_nativeDispose },
diff --git a/services/core/jni/com_android_server_lights_LightsService.cpp b/services/core/jni/com_android_server_lights_LightsService.cpp
index b2b27835274d..3f074f52f443 100644
--- a/services/core/jni/com_android_server_lights_LightsService.cpp
+++ b/services/core/jni/com_android_server_lights_LightsService.cpp
@@ -126,7 +126,7 @@ static void setLight_native(JNIEnv* /* env */, jobject /* clazz */, jlong ptr,
}
}
-static JNINativeMethod method_table[] = {
+static const JNINativeMethod method_table[] = {
{ "init_native", "()J", (void*)init_native },
{ "finalize_native", "(J)V", (void*)finalize_native },
{ "setLight_native", "(JIIIIII)V", (void*)setLight_native },
diff --git a/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp b/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp
index c0a0c9cddba5..774577d43d69 100644
--- a/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp
+++ b/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp
@@ -1023,7 +1023,7 @@ static void RemoveGeofences(
env->ReleaseIntArrayElements(geofenceIdsArray, geofenceIds, 0 /*mode*/);
}
-static JNINativeMethod sMethods[] = {
+static const JNINativeMethod sMethods[] = {
//{"name", "signature", functionPointer }
{"nativeClassInit", "()V", reinterpret_cast<void*>(ClassInit)},
{"nativeInit", "()V", reinterpret_cast<void*>(Init)},
diff --git a/services/core/jni/com_android_server_location_GpsLocationProvider.cpp b/services/core/jni/com_android_server_location_GpsLocationProvider.cpp
index 5c27b1f65f17..b8d4196dad16 100644
--- a/services/core/jni/com_android_server_location_GpsLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GpsLocationProvider.cpp
@@ -1434,7 +1434,7 @@ static void android_location_GpsLocationProvider_configuration_update(JNIEnv* en
env->ReleaseStringUTFChars(config_content, data);
}
-static JNINativeMethod sMethods[] = {
+static const JNINativeMethod sMethods[] = {
/* name, signature, funcPtr */
{"class_init_native", "()V", (void *)android_location_GpsLocationProvider_class_init_native},
{"native_is_supported", "()Z", (void*)android_location_GpsLocationProvider_is_supported},
diff --git a/services/core/jni/com_android_server_power_PowerManagerService.cpp b/services/core/jni/com_android_server_power_PowerManagerService.cpp
index 1662755511f4..2fdb8e2469cd 100644
--- a/services/core/jni/com_android_server_power_PowerManagerService.cpp
+++ b/services/core/jni/com_android_server_power_PowerManagerService.cpp
@@ -166,7 +166,7 @@ static void nativeSetFeature(JNIEnv *env, jclass clazz, jint featureId, jint dat
// ----------------------------------------------------------------------------
-static JNINativeMethod gPowerManagerServiceMethods[] = {
+static const JNINativeMethod gPowerManagerServiceMethods[] = {
/* name, signature, funcPtr */
{ "nativeInit", "()V",
(void*) nativeInit },
diff --git a/services/core/jni/com_android_server_tv_TvInputHal.cpp b/services/core/jni/com_android_server_tv_TvInputHal.cpp
index 507bc9cb5269..89b2a47d73c6 100644
--- a/services/core/jni/com_android_server_tv_TvInputHal.cpp
+++ b/services/core/jni/com_android_server_tv_TvInputHal.cpp
@@ -662,7 +662,7 @@ static void nativeClose(JNIEnv* env, jclass clazz, jlong ptr) {
delete tvInputHal;
}
-static JNINativeMethod gTvInputHalMethods[] = {
+static const JNINativeMethod gTvInputHalMethods[] = {
/* name, signature, funcPtr */
{ "nativeOpen", "(Landroid/os/MessageQueue;)J",
(void*) nativeOpen },
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 67e57034cf91..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;
@@ -73,6 +75,7 @@ import android.os.Environment;
import android.os.FileUtils;
import android.os.Handler;
import android.os.IBinder;
+import android.os.Looper;
import android.os.PersistableBundle;
import android.os.PowerManager;
import android.os.PowerManagerInternal;
@@ -111,6 +114,7 @@ import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager;
import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.JournaledFile;
@@ -266,17 +270,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
| DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS;
final Context mContext;
+ final Injector mInjector;
+ final IPackageManager mIPackageManager;
final UserManager mUserManager;
- final PowerManager.WakeLock mWakeLock;
final LocalService mLocalService;
- final PowerManager mPowerManager;
- final PowerManagerInternal mPowerManagerInternal;
-
- IWindowManager mIWindowManager;
- NotificationManager mNotificationManager;
-
// Stores and loads state on device and profile owners.
private final Owners mOwners;
@@ -346,7 +345,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
final SparseArray<DevicePolicyData> mUserData = new SparseArray<>();
- Handler mHandler = new Handler();
+ final Handler mHandler;
BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
@@ -992,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 = AppGlobals.getPackageManager();
synchronized (this) {
for (int i = policy.mAdminList.size() - 1; i >= 0; i--) {
ActiveAdmin aa = policy.mAdminList.get(i);
@@ -1001,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());
@@ -1024,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);
@@ -1037,18 +1035,145 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
/**
+ * Unit test will subclass it to inject mocks.
+ */
+ @VisibleForTesting
+ static class Injector {
+
+ private final Context mContext;
+
+ Injector(Context context) {
+ mContext = context;
+ }
+
+ Owners newOwners() {
+ return new Owners(mContext);
+ }
+
+ UserManager getUserManager() {
+ return UserManager.get(mContext);
+ }
+
+ NotificationManager getNotificationManager() {
+ return mContext.getSystemService(NotificationManager.class);
+ }
+
+ PowerManagerInternal getPowerManagerInternal() {
+ return LocalServices.getService(PowerManagerInternal.class);
+ }
+
+ IWindowManager getIWindowManager() {
+ return IWindowManager.Stub
+ .asInterface(ServiceManager.getService(Context.WINDOW_SERVICE));
+ }
+
+ IActivityManager getIActivityManager() {
+ return ActivityManagerNative.getDefault();
+ }
+
+ IPackageManager getIPackageManager() {
+ return AppGlobals.getPackageManager();
+ }
+
+ IBackupManager getIBackupManager() {
+ return IBackupManager.Stub.asInterface(
+ ServiceManager.getService(Context.BACKUP_SERVICE));
+ }
+
+ IAudioService getIAudioService() {
+ return IAudioService.Stub.asInterface(ServiceManager.getService(Context.AUDIO_SERVICE));
+ }
+
+ LockPatternUtils newLockPatternUtils() {
+ return new LockPatternUtils(mContext);
+ }
+
+ Looper getMyLooper() {
+ return Looper.myLooper();
+ }
+
+ long binderClearCallingIdentity() {
+ return Binder.clearCallingIdentity();
+ }
+
+ void binderRestoreCallingIdentity(long token) {
+ Binder.restoreCallingIdentity(token);
+ }
+
+ int binderGetCallingUid() {
+ return Binder.getCallingUid();
+ }
+
+ int binderGetCallingPid() {
+ return Binder.getCallingPid();
+ }
+
+ UserHandle binderGetCallingUserHandle() {
+ return Binder.getCallingUserHandle();
+ }
+
+ boolean binderIsCallingUidMyUid() {
+ return getCallingUid() == Process.myUid();
+ }
+
+ File environmentGetUserSystemDirectory(int userId) {
+ return Environment.getUserSystemDirectory(userId);
+ }
+
+ void powerManagerGoToSleep(long time, int reason, int flags) {
+ mContext.getSystemService(PowerManager.class).goToSleep(time, reason, flags);
+ }
+
+ 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;
- mOwners = new Owners(mContext);
- mUserManager = UserManager.get(mContext);
- mHasFeature = context.getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_DEVICE_ADMIN);
- mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
- mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
- mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "DPM");
+ 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(injector.getUserManager());
+ mIPackageManager = Preconditions.checkNotNull(injector.getIPackageManager());
+
mLocalService = new LocalService();
+
+ mHasFeature = mContext.getPackageManager()
+ .hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN);
if (!mHasFeature) {
// Skip the rest of the initialization
return;
@@ -1060,17 +1185,17 @@ 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);
}
@@ -1080,6 +1205,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
* @param userHandle the user for whom to load the policy data
* @return
*/
+ @NonNull
DevicePolicyData getUserData(int userHandle) {
synchronized (this) {
DevicePolicyData policy = mUserData.get(userHandle);
@@ -1103,17 +1229,17 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
* @return
*/
DevicePolicyData getUserDataUnchecked(int userHandle) {
- long ident = Binder.clearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
return getUserData(userHandle);
} finally {
- Binder.restoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
}
void removeUserData(int userHandle) {
synchronized (this) {
- if (userHandle == UserHandle.USER_OWNER) {
+ if (userHandle == UserHandle.USER_SYSTEM) {
Slog.w(LOG_TAG, "Tried to remove device policy file for user 0! Ignoring.");
return;
}
@@ -1124,7 +1250,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (policy != null) {
mUserData.remove(userHandle);
}
- File policyFile = new File(Environment.getUserSystemDirectory(userHandle),
+ File policyFile = new File(mInjector.environmentGetUserSystemDirectory(userHandle),
DEVICE_POLICIES_XML);
policyFile.delete();
Slog.i(LOG_TAG, "Removed device policy file " + policyFile.getAbsolutePath());
@@ -1164,7 +1290,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
alarmTime = now + alarmInterval;
}
- long token = Binder.clearCallingIdentity();
+ long token = mInjector.binderClearCallingIdentity();
try {
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
PendingIntent pi = PendingIntent.getBroadcastAsUser(context, REQUEST_EXPIRE_PASSWORD,
@@ -1176,24 +1302,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
am.set(AlarmManager.RTC, alarmTime, pi);
}
} finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- private IWindowManager getWindowManager() {
- if (mIWindowManager == null) {
- IBinder b = ServiceManager.getService(Context.WINDOW_SERVICE);
- mIWindowManager = IWindowManager.Stub.asInterface(b);
- }
- return mIWindowManager;
- }
-
- private NotificationManager getNotificationManager() {
- if (mNotificationManager == null) {
- mNotificationManager =
- (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+ mInjector.binderRestoreCallingIdentity(token);
}
- return mNotificationManager;
}
ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who, int userHandle) {
@@ -1208,7 +1318,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy)
throws SecurityException {
- final int callingUid = Binder.getCallingUid();
+ final int callingUid = mInjector.binderGetCallingUid();
ActiveAdmin result = getActiveAdminWithPolicyForUidLocked(who, reqPolicy, callingUid);
if (result != null) {
@@ -1232,7 +1342,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
+ admin.info.getTagForPolicy(reqPolicy));
} else {
throw new SecurityException("No active admin owned by uid "
- + Binder.getCallingUid() + " for policy #" + reqPolicy);
+ + mInjector.binderGetCallingUid() + " for policy #" + reqPolicy);
}
}
@@ -1248,7 +1358,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
if (admin.getUid() != uid) {
throw new SecurityException("Admin " + who + " is not owned by uid "
- + Binder.getCallingUid());
+ + mInjector.binderGetCallingUid());
}
if (isActiveAdminWithPolicyForUserLocked(admin, reqPolicy, userId)) {
return admin;
@@ -1275,12 +1385,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
&& !hasUserSetupCompleted(userId);
if (reqPolicy == DeviceAdminInfo.USES_POLICY_DEVICE_OWNER) {
- if ((userId == UserHandle.USER_OWNER && (ownsDevice || ownsInitialization))
+ if ((userId == UserHandle.USER_SYSTEM && (ownsDevice || ownsInitialization))
|| (ownsDevice && ownsProfile)) {
return true;
}
} else if (reqPolicy == DeviceAdminInfo.USES_POLICY_PROFILE_OWNER) {
- if ((userId == UserHandle.USER_OWNER && ownsDevice) || ownsProfile
+ if ((userId == UserHandle.USER_SYSTEM && ownsDevice) || ownsProfile
|| ownsInitialization) {
return true;
}
@@ -1410,11 +1520,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
- private static JournaledFile makeJournaledFile(int userHandle) {
- final String base = userHandle == 0
- ? "/data/system/" + DEVICE_POLICIES_XML
- : new File(Environment.getUserSystemDirectory(userHandle), DEVICE_POLICIES_XML)
- .getAbsolutePath();
+ private JournaledFile makeJournaledFile(int userHandle) {
+ final String base = userHandle == UserHandle.USER_SYSTEM
+ ? mInjector.getDevicePolicyFilePathForSystemUser() + DEVICE_POLICIES_XML
+ : new File(mInjector.environmentGetUserSystemDirectory(userHandle),
+ DEVICE_POLICIES_XML).getAbsolutePath();
return new JournaledFile(new File(base), new File(base + ".tmp"));
}
@@ -1513,6 +1623,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
journal.commit();
sendChangedNotification(userHandle);
} catch (IOException e) {
+ Slog.w(LOG_TAG, "failed writing file", e);
try {
if (stream != null) {
stream.close();
@@ -1527,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 = Binder.clearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
mContext.sendBroadcastAsUser(intent, new UserHandle(userHandle));
} finally {
- Binder.restoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
}
@@ -1663,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 = Binder.clearCallingIdentity();
+ final long identity = mInjector.binderClearCallingIdentity();
try {
- LockPatternUtils utils = new LockPatternUtils(mContext);
+ LockPatternUtils utils = mInjector.newLockPatternUtils();
if (utils.getActivePasswordQuality(userHandle) < policy.mActivePasswordQuality) {
Slog.w(LOG_TAG, "Active password quality 0x"
+ Integer.toHexString(policy.mActivePasswordQuality)
@@ -1681,7 +1792,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
policy.mActivePasswordNonLetter = 0;
}
} finally {
- Binder.restoreCallingIdentity(identity);
+ mInjector.binderRestoreCallingIdentity(identity);
}
validatePasswordOwnerLocked(policy);
@@ -1695,26 +1806,26 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
private void updateLockTaskPackagesLocked(List<String> packages, int userId) {
- IActivityManager am = ActivityManagerNative.getDefault();
- long ident = Binder.clearCallingIdentity();
+ 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 {
- Binder.restoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
}
private void updateDeviceOwnerLocked() {
- IActivityManager am = ActivityManagerNative.getDefault();
- long ident = Binder.clearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
- am.updateDeviceOwner(getDeviceOwner());
+ mInjector.getIActivityManager()
+ .updateDeviceOwner(getDeviceOwner());
} catch (RemoteException e) {
// Not gonna happen.
} finally {
- Binder.restoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
}
@@ -1759,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 = SystemProperties.getBoolean(cameraPropertyForUser, false);
+ boolean systemState = mInjector.systemPropertiesGetBoolean(cameraPropertyForUser, false);
boolean cameraDisabled = getCameraDisabled(null, policy.mUserHandle);
if (cameraDisabled != systemState) {
- long token = Binder.clearCallingIdentity();
+ long token = mInjector.binderClearCallingIdentity();
try {
String value = cameraDisabled ? "1" : "0";
if (DBG) Slog.v(LOG_TAG, "Change in camera state ["
+ cameraPropertyForUser + "] = " + value);
- SystemProperties.set(cameraPropertyForUser, value);
+ mInjector.systemPropertiesSet(cameraPropertyForUser, value);
} finally {
- Binder.restoreCallingIdentity(token);
+ mInjector.binderRestoreCallingIdentity(token);
}
}
}
@@ -1789,7 +1900,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
private void onLockSettingsReady() {
- getUserData(UserHandle.USER_OWNER);
+ getUserData(UserHandle.USER_SYSTEM);
loadOwners();
cleanUpOldUsers();
// Register an observer for watching for user setup complete.
@@ -1809,14 +1920,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
private void ensureDeviceOwnerUserStarted() {
if (mOwners.hasDeviceOwner()) {
- final IActivityManager am = ActivityManagerNative.getDefault();
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.
@@ -1917,7 +2027,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Log.e(LOG_TAG, "Could not connect to KeyChain service", e);
}
if (!hasCert) {
- getNotificationManager().cancelAsUser(
+ mInjector.getNotificationManager().cancelAsUser(
null, MONITORING_CERT_NOTIFICATION_ID, userHandle);
return;
}
@@ -1962,7 +2072,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
com.android.internal.R.color.system_notification_accent_color))
.build();
- getNotificationManager().notifyAsUser(
+ mInjector.getNotificationManager().notifyAsUser(
null, MONITORING_CERT_NOTIFICATION_ID, noti, userHandle);
}
}
@@ -1991,7 +2101,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
throw new IllegalArgumentException("Bad admin: " + adminReceiver);
}
synchronized (this) {
- long ident = Binder.clearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
if (!refreshing
&& getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null) {
@@ -2018,7 +2128,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
sendAdminCommandLocked(newAdmin, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED,
onEnableData, null);
} finally {
- Binder.restoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
}
}
@@ -2112,7 +2222,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (admin == null) {
return;
}
- if (admin.getUid() != Binder.getCallingUid()) {
+ if (admin.getUid() != mInjector.binderGetCallingUid()) {
// Active device owners must remain active admins.
if (isDeviceOwner(adminReceiver.getPackageName())) {
return;
@@ -2120,11 +2230,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.MANAGE_DEVICE_ADMINS, null);
}
- long ident = Binder.clearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
removeActiveAdminLocked(adminReceiver, userHandle);
} finally {
- Binder.restoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
}
}
@@ -2394,7 +2504,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|| activeAdmin.crossProfileWidgetProviders.isEmpty()) {
return null;
}
- if (Binder.getCallingUid() == Process.myUid()) {
+ if (mInjector.binderIsCallingUidMyUid()) {
return new ArrayList<>(activeAdmin.crossProfileWidgetProviders);
} else {
return activeAdmin.crossProfileWidgetProviders;
@@ -2959,7 +3069,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
- int callingUid = Binder.getCallingUid();
+ 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");
@@ -2975,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 = Binder.clearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
LockPatternUtils utils = new LockPatternUtils(mContext);
if (!TextUtils.isEmpty(password)) {
@@ -2996,7 +3106,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
} finally {
- Binder.restoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
return true;
@@ -3004,10 +3114,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
private void setDoNotAskCredentialsOnBoot() {
synchronized (this) {
- DevicePolicyData policyData = getUserData(UserHandle.USER_OWNER);
+ DevicePolicyData policyData = getUserData(UserHandle.USER_SYSTEM);
if (!policyData.doNotAskCredentialsOnBoot) {
policyData.doNotAskCredentialsOnBoot = true;
- saveSettingsLocked(UserHandle.USER_OWNER);
+ saveSettingsLocked(UserHandle.USER_SYSTEM);
}
}
}
@@ -3017,7 +3127,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.QUERY_DO_NOT_ASK_CREDENTIALS_ON_BOOT, null);
synchronized (this) {
- DevicePolicyData policyData = getUserData(UserHandle.USER_OWNER);
+ DevicePolicyData policyData = getUserData(UserHandle.USER_SYSTEM);
return policyData.doNotAskCredentialsOnBoot;
}
}
@@ -3046,7 +3156,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return;
}
- long ident = Binder.clearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
if (timeMs <= 0) {
timeMs = Integer.MAX_VALUE;
@@ -3058,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 {
- Binder.restoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
}
@@ -3112,26 +3224,21 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
private void lockNowUnchecked() {
- long ident = Binder.clearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
// Power off the display
- mPowerManager.goToSleep(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);
- getWindowManager().lockNow(null);
+ mInjector.getIWindowManager().lockNow(null);
} catch (RemoteException e) {
} finally {
- Binder.restoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
}
- private boolean isExtStorageEncrypted() {
- String state = SystemProperties.get("vold.decrypt");
- return !"".equals(state);
- }
-
@Override
public void enforceCanManageCaCerts(ComponentName who) {
if (who == null) {
@@ -3146,7 +3253,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
private boolean isCallerDelegatedCertInstaller() {
- final int callingUid = Binder.getCallingUid();
+ final int callingUid = mInjector.binderGetCallingUid();
final int userHandle = UserHandle.getUserId(callingUid);
synchronized (this) {
final DevicePolicyData policy = getUserData(userHandle);
@@ -3181,7 +3288,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId());
- final long id = Binder.clearCallingIdentity();
+ final long id = mInjector.binderClearCallingIdentity();
try {
final KeyChainConnection keyChainConnection = KeyChain.bindAsUser(mContext, userHandle);
try {
@@ -3196,7 +3303,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Log.w(LOG_TAG, "installCaCertsToKeyChain(): ", e1);
Thread.currentThread().interrupt();
} finally {
- Binder.restoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
return false;
}
@@ -3212,7 +3319,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
enforceCanManageCaCerts(admin);
final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId());
- final long id = Binder.clearCallingIdentity();
+ final long id = mInjector.binderClearCallingIdentity();
try {
final KeyChainConnection keyChainConnection = KeyChain.bindAsUser(mContext, userHandle);
try {
@@ -3228,7 +3335,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Log.w(LOG_TAG, "CaCertUninstaller: ", ie);
Thread.currentThread().interrupt();
} finally {
- Binder.restoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
}
@@ -3244,7 +3351,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId());
- final long id = Binder.clearCallingIdentity();
+ final long id = mInjector.binderClearCallingIdentity();
try {
final KeyChainConnection keyChainConnection = KeyChain.bindAsUser(mContext, userHandle);
try {
@@ -3259,7 +3366,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Log.w(LOG_TAG, "Interrupted while installing certificate", e);
Thread.currentThread().interrupt();
} finally {
- Binder.restoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
return false;
}
@@ -3268,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(Binder.getCallingUid()) != Process.SYSTEM_UID) {
+ if (UserHandle.getAppId(mInjector.binderGetCallingUid()) != Process.SYSTEM_UID) {
return;
}
- final UserHandle caller = Binder.getCallingUserHandle();
+ 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()) {
@@ -3293,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 = Binder.clearCallingIdentity();
+ final long id = mInjector.binderClearCallingIdentity();
try {
mContext.sendOrderedBroadcastAsUser(intent, caller, null, new BroadcastReceiver() {
@Override
@@ -3303,7 +3410,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}, null, Activity.RESULT_OK, null, null);
} finally {
- Binder.restoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
}
@@ -3372,20 +3479,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
final ActiveAdmin admin = getActiveAdminForCallerLocked(null,
DeviceAdminInfo.USES_POLICY_WIPE_DATA);
- final String source;
- final ComponentName cname = admin.info.getComponent();
- if (cname != null) {
- source = cname.flattenToShortString();
- } else {
- source = admin.info.getPackageName();
- }
+ final String source = admin.info.getComponent().flattenToShortString();
- long ident = Binder.clearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
if ((flags & WIPE_RESET_PROTECTION_DATA) != 0) {
boolean ownsInitialization = isDeviceInitializer(admin.info.getPackageName())
&& !hasUserSetupCompleted(userHandle);
- if (userHandle != UserHandle.USER_OWNER
+ if (userHandle != UserHandle.USER_SYSTEM
|| !(isDeviceOwner(admin.info.getPackageName())
|| ownsInitialization)) {
throw new SecurityException(
@@ -3401,22 +3502,22 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
wipeDeviceOrUserLocked(wipeExtRequested, userHandle,
"DevicePolicyManager.wipeData() from " + source);
} finally {
- Binder.restoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
}
}
private void wipeDeviceOrUserLocked(boolean wipeExtRequested, final int userHandle, String reason) {
- if (userHandle == UserHandle.USER_OWNER) {
+ if (userHandle == UserHandle.USER_SYSTEM) {
wipeDataLocked(wipeExtRequested, reason);
} else {
mHandler.post(new Runnable() {
@Override
public void run() {
try {
- IActivityManager am = ActivityManagerNative.getDefault();
+ IActivityManager am = mInjector.getIActivityManager();
if (am.getCurrentUser().id == userHandle) {
- am.switchUser(UserHandle.USER_OWNER);
+ am.switchUser(UserHandle.USER_SYSTEM);
}
boolean isManagedProfile = isManagedProfile(userHandle);
@@ -3442,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();
- getNotificationManager().notify(PROFILE_WIPED_NOTIFICATION_ID, notification);
+ mInjector.getNotificationManager().notify(PROFILE_WIPED_NOTIFICATION_ID, notification);
}
private void clearWipeProfileNotification() {
- getNotificationManager().cancel(PROFILE_WIPED_NOTIFICATION_ID);
+ mInjector.getNotificationManager().cancel(PROFILE_WIPED_NOTIFICATION_ID);
}
@Override
@@ -3506,7 +3607,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|| p.mActivePasswordNumeric != numbers
|| p.mActivePasswordSymbols != symbols
|| p.mActivePasswordNonLetter != nonletter) {
- long ident = Binder.clearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
p.mActivePasswordQuality = quality;
p.mActivePasswordLength = length;
@@ -3524,7 +3625,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, userHandle);
} finally {
- Binder.restoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
}
}
@@ -3560,7 +3661,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.BIND_DEVICE_ADMIN, null);
- long ident = Binder.clearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
boolean wipeData = false;
int identifier = 0;
@@ -3591,7 +3692,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
"reportFailedPasswordAttempt()");
}
} finally {
- Binder.restoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
}
@@ -3604,7 +3705,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
synchronized (this) {
DevicePolicyData policy = getUserData(userHandle);
if (policy.mFailedPasswordAttempts != 0 || policy.mPasswordOwner >= 0) {
- long ident = Binder.clearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
policy.mFailedPasswordAttempts = 0;
policy.mPasswordOwner = -1;
@@ -3615,7 +3716,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle);
}
} finally {
- Binder.restoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
}
}
@@ -3630,8 +3731,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
synchronized(this) {
Preconditions.checkNotNull(who, "ComponentName is null");
- // Only check if owner has set global proxy. We don't allow other users to set it.
- DevicePolicyData policy = getUserData(UserHandle.USER_OWNER);
+ // Only check if system user has set global proxy. We don't allow other users to set it.
+ DevicePolicyData policy = getUserData(UserHandle.USER_SYSTEM);
ActiveAdmin admin = getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
@@ -3647,8 +3748,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
- // If the user is not the owner, don't set the global proxy. Fail silently.
- if (UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
+ // If the user is not system, don't set the global proxy. Fail silently.
+ if (UserHandle.getCallingUserId() != UserHandle.USER_SYSTEM) {
Slog.w(LOG_TAG, "Only the owner is allowed to set the global proxy. User "
+ UserHandle.getCallingUserId() + " is not permitted.");
return null;
@@ -3666,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 = Binder.clearCallingIdentity();
+ long origId = mInjector.binderClearCallingIdentity();
try {
resetGlobalProxyLocked(policy);
} finally {
- Binder.restoreCallingIdentity(origId);
+ mInjector.binderRestoreCallingIdentity(origId);
}
return null;
}
@@ -3683,7 +3784,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
enforceCrossUserPermission(userHandle);
synchronized(this) {
- DevicePolicyData policy = getUserData(UserHandle.USER_OWNER);
+ DevicePolicyData policy = getUserData(UserHandle.USER_SYSTEM);
// Scan through active admins and find if anyone has already
// set the global proxy.
final int N = policy.mAdminList.size();
@@ -3705,13 +3806,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
synchronized (this) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
}
- long token = Binder.clearCallingIdentity();
+ long token = mInjector.binderClearCallingIdentity();
try {
ConnectivityManager connectivityManager = (ConnectivityManager)
mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
connectivityManager.setGlobalProxy(proxyInfo);
} finally {
- Binder.restoreCallingIdentity(token);
+ mInjector.binderRestoreCallingIdentity(token);
}
}
@@ -3771,10 +3872,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
final int userHandle = UserHandle.getCallingUserId();
synchronized (this) {
// Check for permissions
- // Only owner can set storage encryption
- if (userHandle != UserHandle.USER_OWNER
- || UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
- Slog.w(LOG_TAG, "Only owner is allowed to set storage encryption. User "
+ // Only system user can set storage encryption
+ if (userHandle != UserHandle.USER_SYSTEM) {
+ Slog.w(LOG_TAG, "Only owner/system user is allowed to set storage encryption. User "
+ UserHandle.getCallingUserId() + " is not permitted.");
return 0;
}
@@ -3793,7 +3893,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
saveSettingsLocked(userHandle);
}
- DevicePolicyData policy = getUserData(UserHandle.USER_OWNER);
+ DevicePolicyData policy = getUserData(UserHandle.USER_SYSTEM);
// (2) Compute "max" for all admins
boolean newRequested = false;
final int N = policy.mAdminList.size();
@@ -3873,15 +3973,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
* {@link DevicePolicyManager#ENCRYPTION_STATUS_ACTIVE}.
*/
private int getEncryptionStatus() {
- String status = SystemProperties.get("ro.crypto.state", "unsupported");
+ String status = mInjector.systemPropertiesGet("ro.crypto.state", "unsupported");
if ("encrypted".equalsIgnoreCase(status)) {
- final long token = Binder.clearCallingIdentity();
+ final long token = mInjector.binderClearCallingIdentity();
try {
return LockPatternUtils.isDeviceEncrypted()
? DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE
: DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_DEFAULT_KEY;
} finally {
- Binder.restoreCallingIdentity(token);
+ mInjector.binderRestoreCallingIdentity(token);
}
} else if ("unencrypted".equalsIgnoreCase(status)) {
return DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE;
@@ -3946,13 +4046,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
private void updateScreenCaptureDisabledInWindowManager(int userHandle, boolean disabled) {
- long ident = Binder.clearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
- getWindowManager().setScreenCaptureDisabled(userHandle, disabled);
+ mInjector.getIWindowManager().setScreenCaptureDisabled(userHandle, disabled);
} catch (RemoteException e) {
Log.w(LOG_TAG, "Unable to notify WindowManager.", e);
} finally {
- Binder.restoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
}
@@ -3977,12 +4077,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
// Turn AUTO_TIME on in settings if it is required
if (required) {
- long ident = Binder.clearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.AUTO_TIME, 1 /* AUTO_TIME on */);
} finally {
- Binder.restoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
}
}
@@ -4091,7 +4191,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return 0;
}
enforceCrossUserPermission(userHandle);
- long ident = Binder.clearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
synchronized (this) {
if (who != null) {
@@ -4134,7 +4234,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return which;
}
} finally {
- Binder.restoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
}
@@ -4144,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");
}
@@ -4152,15 +4252,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
enforceCanSetDeviceOwner(userId);
// Shutting down backup manager service permanently.
- long ident = Binder.clearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
- IBackupManager ibm = IBackupManager.Stub.asInterface(
- ServiceManager.getService(Context.BACKUP_SERVICE));
- ibm.setBackupServiceActive(UserHandle.USER_OWNER, false);
+ mInjector.getIBackupManager().setBackupServiceActive(UserHandle.USER_SYSTEM, false);
} catch (RemoteException e) {
throw new IllegalStateException("Failed deactivating backup service.", e);
} finally {
- Binder.restoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
mOwners.setDeviceOwner(packageName, ownerName, userId);
@@ -4168,12 +4266,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
updateDeviceOwnerLocked();
Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED);
- ident = Binder.clearCallingIdentity();
+ ident = mInjector.binderClearCallingIdentity();
try {
// TODO Send to system too?
mContext.sendBroadcastAsUser(intent, new UserHandle(userId));
} finally {
- Binder.restoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
return true;
}
@@ -4205,13 +4303,16 @@ 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_OWNER);
+ return getApplicationLabel(deviceOwnerPackage, UserHandle.USER_SYSTEM);
}
}
@@ -4222,7 +4323,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return null;
}
- DevicePolicyData policy = getUserData(UserHandle.USER_OWNER);
+ DevicePolicyData policy = getUserData(UserHandle.USER_SYSTEM);
final int n = policy.mAdminList.size();
for (int i = 0; i < n; i++) {
ActiveAdmin admin = policy.mAdminList.get(i);
@@ -4238,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 != Binder.getCallingUid()) {
+ if (uid != mInjector.binderGetCallingUid()) {
throw new SecurityException("Invalid packageName");
}
} catch (NameNotFoundException e) {
@@ -4248,21 +4349,19 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
throw new SecurityException("clearDeviceOwner can only be called by the device owner");
}
synchronized (this) {
- clearUserPoliciesLocked(new UserHandle(UserHandle.USER_OWNER));
+ clearUserPoliciesLocked(new UserHandle(UserHandle.USER_SYSTEM));
mOwners.clearDeviceOwner();
mOwners.writeDeviceOwner();
updateDeviceOwnerLocked();
// Reactivate backup service.
- long ident = Binder.clearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
- IBackupManager ibm = IBackupManager.Stub.asInterface(
- ServiceManager.getService(Context.BACKUP_SERVICE));
- ibm.setBackupServiceActive(UserHandle.USER_OWNER, true);
+ mInjector.getIBackupManager().setBackupServiceActive(UserHandle.USER_SYSTEM, true);
} catch (RemoteException e) {
throw new IllegalStateException("Failed reactivating backup service.", e);
} finally {
- Binder.restoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
}
}
@@ -4274,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(AppGlobals.getPackageManager(),
- initializer.getPackageName(), Binder.getCallingUserHandle().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);
@@ -4365,9 +4465,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
ActiveAdmin admin = getActiveAdminUncheckedLocked(who, UserHandle.getCallingUserId());
- if (admin.getUid() != Binder.getCallingUid()) {
+ if (admin.getUid() != mInjector.binderGetCallingUid()) {
throw new SecurityException("Admin " + who + " is not owned by uid "
- + Binder.getCallingUid());
+ + mInjector.binderGetCallingUid());
}
if (!isDeviceInitializer(admin.info.getPackageName())
@@ -4376,12 +4476,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
"clearDeviceInitializer can only be called by the device initializer/owner");
}
synchronized (this) {
- long ident = Binder.clearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
mOwners.clearDeviceInitializer();
mOwners.writeDeviceOwner();
} finally {
- Binder.restoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
}
}
@@ -4392,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);
}
@@ -4409,7 +4509,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (!mHasFeature) {
return;
}
- UserHandle callingUser = Binder.getCallingUserHandle();
+ UserHandle callingUser = mInjector.binderGetCallingUserHandle();
// Check if this is the profile owner who is calling
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
synchronized (this) {
@@ -4429,15 +4529,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
policy.mStatusBarDisabled = false;
saveSettingsLocked(userId);
- final long ident = Binder.clearCallingIdentity();
+ final long ident = mInjector.binderClearCallingIdentity();
try {
clearUserRestrictions(userHandle);
- AppGlobals.getPackageManager().updatePermissionFlagsForAllApps(
+ mIPackageManager.updatePermissionFlagsForAllApps(
PackageManager.FLAG_PERMISSION_POLICY_FIXED,
0 /* flagValues */, userHandle.getIdentifier());
} catch (RemoteException re) {
} finally {
- Binder.restoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
}
@@ -4445,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.
@@ -4457,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.
@@ -4474,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
@@ -4497,18 +4593,17 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
"This method can only be called by device initializers");
}
- long id = Binder.clearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
if (!isDeviceOwner(activeAdmin.info.getPackageName())) {
- IPackageManager ipm = AppGlobals.getPackageManager();
- ipm.setComponentEnabledSetting(who,
+ mIPackageManager.setComponentEnabledSetting(who,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP, userId);
removeActiveAdmin(who, userId);
}
- if (userId == UserHandle.USER_OWNER) {
+ if (userId == UserHandle.USER_SYSTEM) {
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.DEVICE_PROVISIONED, 1);
}
@@ -4518,7 +4613,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Log.i(LOG_TAG, "Can't talk to package manager", e);
return false;
} finally {
- restoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
return true;
}
@@ -4536,7 +4631,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
int userId = UserHandle.getCallingUserId();
- long id = Binder.clearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
mUserManager.setUserEnabled(userId);
UserInfo parent = mUserManager.getProfileParent(userId);
@@ -4546,7 +4641,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Intent.FLAG_RECEIVER_FOREGROUND);
mContext.sendBroadcastAsUser(intent, new UserHandle(parent.id));
} finally {
- restoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
}
}
@@ -4558,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 = Binder.clearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
mUserManager.setUserName(userId, profileName);
} finally {
- restoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
}
@@ -4612,7 +4707,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
* Canonical name for a given package.
*/
private String getApplicationLabel(String packageName, int userHandle) {
- long token = Binder.clearCallingIdentity();
+ long token = mInjector.binderClearCallingIdentity();
try {
final Context userContext;
try {
@@ -4630,7 +4725,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
return result != null ? result.toString() : null;
} finally {
- Binder.restoreCallingIdentity(token);
+ mInjector.binderRestoreCallingIdentity(token);
}
}
@@ -4656,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 = Binder.getCallingUid();
+ int callingUid = mInjector.binderGetCallingUid();
if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) {
if (hasUserSetupCompleted(userHandle) &&
AccountManager.get(mContext).getAccountsAsUser(userHandle).length > 0) {
@@ -4689,13 +4784,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
throw new IllegalStateException("User not running: " + userId);
}
- int callingUid = Binder.getCallingUid();
+ int callingUid = mInjector.binderGetCallingUid();
if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) {
- if (!hasUserSetupCompleted(UserHandle.USER_OWNER)) {
+ 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 "
@@ -4714,8 +4809,8 @@ 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 (hasUserSetupCompleted(UserHandle.USER_OWNER)) {
+ if (!mInjector.userManagerIsSplitSystemUser()) {
+ if (hasUserSetupCompleted(UserHandle.USER_SYSTEM)) {
throw new IllegalStateException("Cannot set the device owner if the device is "
+ "already set-up");
}
@@ -4726,7 +4821,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (userHandle < 0) {
throw new IllegalArgumentException("Invalid userId " + userHandle);
}
- final int callingUid = Binder.getCallingUid();
+ final int callingUid = mInjector.binderGetCallingUid();
if (userHandle == UserHandle.getUserId(callingUid)) return;
if (callingUid != Process.SYSTEM_UID && callingUid != 0) {
mContext.enforceCallingOrSelfPermission(
@@ -4742,32 +4837,31 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
private UserInfo getProfileParent(int userHandle) {
- long ident = Binder.clearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
return mUserManager.getProfileParent(userHandle);
} finally {
- Binder.restoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
}
private boolean isManagedProfile(int userHandle) {
- long ident = Binder.clearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
return mUserManager.getUserInfo(userHandle).isManagedProfile();
} finally {
- Binder.restoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
}
private void enableIfNecessary(String packageName, int userId) {
try {
- IPackageManager ipm = AppGlobals.getPackageManager();
- 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");
}
@@ -4781,8 +4875,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
!= PackageManager.PERMISSION_GRANTED) {
pw.println("Permission Denial: can't dump DevicePolicyManagerService from from pid="
- + Binder.getCallingPid()
- + ", uid=" + Binder.getCallingUid());
+ + mInjector.binderGetCallingPid()
+ + ", uid=" + mInjector.binderGetCallingUid());
return;
}
@@ -4823,14 +4917,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
synchronized (this) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
- IPackageManager pm = AppGlobals.getPackageManager();
- long id = Binder.clearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
- pm.addPersistentPreferredActivity(filter, activity, userHandle);
+ mIPackageManager.addPersistentPreferredActivity(filter, activity, userHandle);
} catch (RemoteException re) {
// Shouldn't happen
} finally {
- restoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
}
}
@@ -4842,14 +4935,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
synchronized (this) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
- IPackageManager pm = AppGlobals.getPackageManager();
- long id = Binder.clearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
- pm.clearPackagePersistentPreferredActivities(packageName, userHandle);
+ mIPackageManager.clearPackagePersistentPreferredActivities(packageName, userHandle);
} catch (RemoteException re) {
// Shouldn't happen
} finally {
- restoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
}
}
@@ -4861,11 +4953,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
synchronized (this) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
- long id = Binder.clearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
mUserManager.setApplicationRestrictions(packageName, settings, userHandle);
} finally {
- restoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
}
}
@@ -4963,7 +5055,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
@Override
public ComponentName getRestrictionsProvider(int userHandle) {
synchronized (this) {
- if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+ if (mInjector.binderGetCallingUid() != Process.SYSTEM_UID) {
throw new SecurityException("Only the system can query the permission provider");
}
DevicePolicyData userData = getUserData(userHandle);
@@ -4978,8 +5070,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
synchronized (this) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
- IPackageManager pm = AppGlobals.getPackageManager();
- long id = Binder.clearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
UserInfo parent = mUserManager.getProfileParent(callingUserId);
if (parent == null) {
@@ -4988,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 {
- restoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
}
}
@@ -5009,8 +5100,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
int callingUserId = UserHandle.getCallingUserId();
synchronized (this) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
- IPackageManager pm = AppGlobals.getPackageManager();
- long id = Binder.clearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
UserInfo parent = mUserManager.getProfileParent(callingUserId);
if (parent == null) {
@@ -5019,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 {
- restoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
}
}
@@ -5039,7 +5130,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
private boolean checkPackagesInPermittedListOrSystem(List<String> enabledPackages,
List<String> permittedList) {
int userIdToCheck = UserHandle.getCallingUserId();
- long id = Binder.clearCallingIdentity();
+ 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.
@@ -5048,12 +5139,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
userIdToCheck = user.profileGroupId;
}
- IPackageManager pm = AppGlobals.getPackageManager();
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);
@@ -5063,7 +5153,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
} finally {
- restoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
return true;
}
@@ -5088,7 +5178,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (packageList != null) {
int userId = UserHandle.getCallingUserId();
List<AccessibilityServiceInfo> enabledServices = null;
- long id = Binder.clearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
UserInfo user = mUserManager.getUserInfo(userId);
if (user.isManagedProfile()) {
@@ -5098,7 +5188,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
enabledServices = accessibilityManager.getEnabledAccessibilityServiceList(
AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
} finally {
- restoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
if (enabledServices != null) {
@@ -5169,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 = Binder.clearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
UserInfo user = mUserManager.getUserInfo(userId);
if (user.isManagedProfile()) {
@@ -5180,7 +5270,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
List<AccessibilityServiceInfo> installedServices =
accessibilityManager.getInstalledAccessibilityServiceList();
- IPackageManager pm = AppGlobals.getPackageManager();
if (installedServices != null) {
for (AccessibilityServiceInfo service : installedServices) {
ServiceInfo serviceInfo = service.getResolveInfo().serviceInfo;
@@ -5191,7 +5280,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
} finally {
- restoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
}
@@ -5201,12 +5290,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
private boolean checkCallerIsCurrentUserOrProfile() {
int callingUserId = UserHandle.getCallingUserId();
- long token = Binder.clearCallingIdentity();
+ long token = mInjector.binderClearCallingIdentity();
try {
UserInfo currentUser;
UserInfo callingUser = mUserManager.getUserInfo(callingUserId);
try {
- currentUser = ActivityManagerNative.getDefault().getCurrentUser();
+ currentUser = mInjector.getIActivityManager().getCurrentUser();
} catch (RemoteException e) {
Slog.e(LOG_TAG, "Failed to talk to activity managed.", e);
return false;
@@ -5223,7 +5312,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return false;
}
} finally {
- Binder.restoreCallingIdentity(token);
+ mInjector.binderRestoreCallingIdentity(token);
}
return true;
}
@@ -5289,7 +5378,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
public List getPermittedInputMethodsForCurrentUser() {
UserInfo currentUser;
try {
- currentUser = ActivityManagerNative.getDefault().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
@@ -5327,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 = Binder.clearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
- IPackageManager pm = AppGlobals.getPackageManager();
if (imes != null) {
for (InputMethodInfo ime : imes) {
ServiceInfo serviceInfo = ime.getServiceInfo();
@@ -5340,7 +5428,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
} finally {
- restoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
}
return result;
@@ -5353,7 +5441,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
synchronized (this) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
- long id = Binder.clearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
UserInfo userInfo = mUserManager.createUser(name, 0 /* flags */);
if (userInfo != null) {
@@ -5361,7 +5449,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
return null;
} finally {
- restoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
}
}
@@ -5373,21 +5461,19 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (user == null) {
return null;
}
- long id = Binder.clearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
String profileOwnerPkg = profileOwnerComponent.getPackageName();
- final IPackageManager ipm = AppGlobals.getPackageManager();
- IActivityManager activityManager = ActivityManagerNative.getDefault();
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);
}
@@ -5396,7 +5482,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
setProfileOwner(profileOwnerComponent, ownerName, userHandle);
return user;
} finally {
- restoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
}
@@ -5406,11 +5492,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
synchronized (this) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
- long id = Binder.clearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
return mUserManager.removeUser(userHandle.getIdentifier());
} finally {
- restoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
}
}
@@ -5421,18 +5507,18 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
synchronized (this) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
- long id = Binder.clearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
- int userId = UserHandle.USER_OWNER;
+ int userId = UserHandle.USER_SYSTEM;
if (userHandle != null) {
userId = userHandle.getIdentifier();
}
- return ActivityManagerNative.getDefault().switchUser(userId);
+ return mInjector.getIActivityManager().switchUser(userId);
} catch (RemoteException e) {
Log.e(LOG_TAG, "Couldn't switch user", e);
return false;
} finally {
- restoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
}
}
@@ -5445,14 +5531,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
synchronized (this) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
- long id = Binder.clearCallingIdentity();
+ 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 {
- restoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
}
}
@@ -5460,13 +5546,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
@Override
public void setUserRestriction(ComponentName who, String key, boolean enabled) {
Preconditions.checkNotNull(who, "ComponentName is null");
- final UserHandle user = new UserHandle(UserHandle.getCallingUserId());
- final int userHandle = user.getIdentifier();
+ final int userHandle = UserHandle.getCallingUserId();
+ final UserHandle user = new UserHandle(userHandle);
synchronized (this) {
ActiveAdmin activeAdmin =
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
boolean isDeviceOwner = isDeviceOwner(activeAdmin.info.getPackageName());
- if (!isDeviceOwner && userHandle != UserHandle.USER_OWNER
+ if (!isDeviceOwner && userHandle != UserHandle.USER_SYSTEM
&& DEVICE_OWNER_USER_RESTRICTIONS.contains(key)) {
throw new SecurityException("Profile owners cannot set user restriction " + key);
}
@@ -5475,24 +5561,16 @@ 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 = Binder.clearCallingIdentity();
+ 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);
- }
- if (UserManager.DISALLOW_CONFIG_WIFI.equals(key)) {
+ 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,
userHandle);
@@ -5504,8 +5582,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "",
userHandle);
} else if (UserManager.DISALLOW_DEBUGGING_FEATURES.equals(key)) {
- // Only disable adb if changing for primary user, since it is global
- if (userHandle == UserHandle.USER_OWNER) {
+ // Only disable adb if changing for system user, since it is global
+ // TODO: should this be admin user?
+ if (userHandle == UserHandle.USER_SYSTEM) {
Settings.Global.putStringForUser(mContext.getContentResolver(),
Settings.Global.ADB_ENABLED, "0", userHandle);
}
@@ -5528,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 = SystemProperties.getLong(property, 0) + 1;
- SystemProperties.set(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);
@@ -5538,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 {
- restoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
sendChangedNotification(userHandle);
}
@@ -5562,15 +5641,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
synchronized (this) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
- long id = Binder.clearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
- IPackageManager pm = AppGlobals.getPackageManager();
- 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 {
- restoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
return false;
}
@@ -5583,15 +5662,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
synchronized (this) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
- long id = Binder.clearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
- IPackageManager pm = AppGlobals.getPackageManager();
- 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 {
- restoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
return false;
}
@@ -5606,7 +5685,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
int userId = UserHandle.getCallingUserId();
- long id = Binder.clearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
if (DBG) {
@@ -5622,19 +5701,18 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
primaryUser = um.getUserInfo(userId);
}
- IPackageManager pm = AppGlobals.getPackageManager();
- 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 {
- restoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
}
}
@@ -5648,7 +5726,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
int userId = UserHandle.getCallingUserId();
- long id = Binder.clearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
UserManager um = UserManager.get(mContext);
@@ -5659,8 +5737,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
primaryUser = um.getUserInfo(userId);
}
- IPackageManager pm = AppGlobals.getPackageManager();
- List<ResolveInfo> activitiesToEnable = pm.queryIntentActivities(intent,
+ List<ResolveInfo> activitiesToEnable = mIPackageManager.queryIntentActivities(
+ intent,
intent.resolveTypeIfNeeded(mContext.getContentResolver()),
0, // no flags
primaryUser.id);
@@ -5671,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");
@@ -5687,7 +5765,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Slog.wtf(LOG_TAG, "Failed to resolve intent for: " + intent);
return 0;
} finally {
- restoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
}
}
@@ -5753,15 +5831,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
synchronized (this) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
- long id = Binder.clearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
- IPackageManager pm = AppGlobals.getPackageManager();
- 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 {
- restoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
}
}
@@ -5778,15 +5855,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
}
- long id = Binder.clearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
- IPackageManager pm = AppGlobals.getPackageManager();
- 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 {
- restoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
}
return false;
@@ -5838,7 +5914,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
actualLookupKey, actualContactId, originalIntent);
final int callingUserId = UserHandle.getCallingUserId();
- final long ident = Binder.clearCallingIdentity();
+ final long ident = mInjector.binderClearCallingIdentity();
try {
synchronized (this) {
final int managedUserId = getManagedUserId(callingUserId);
@@ -5856,7 +5932,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
mContext, intent, new UserHandle(managedUserId));
}
} finally {
- Binder.restoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
}
@@ -5937,7 +6013,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
synchronized (this) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
- int userHandle = Binder.getCallingUserHandle().getIdentifier();
+ int userHandle = mInjector.binderGetCallingUserHandle().getIdentifier();
setLockTaskPackagesLocked(userHandle, new ArrayList<>(Arrays.asList(packages)));
}
}
@@ -5959,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 = Binder.getCallingUserHandle().getIdentifier();
+ int userHandle = mInjector.binderGetCallingUserHandle().getIdentifier();
final List<String> packages = getLockTaskPackagesLocked(userHandle);
return packages.toArray(new String[packages.size()]);
}
@@ -5978,7 +6054,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
@Override
public boolean isLockTaskPermitted(String pkg) {
// Get current user's devicepolicy
- int uid = Binder.getCallingUid();
+ int uid = mInjector.binderGetCallingUid();
int userHandle = UserHandle.getUserId(uid);
DevicePolicyData policy = getUserData(userHandle);
synchronized (this) {
@@ -5997,7 +6073,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
@Override
public void notifyLockTaskModeChanged(boolean isEnabled, String pkg, int userHandle) {
- if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+ if (mInjector.binderGetCallingUid() != Process.SYSTEM_UID) {
throw new SecurityException("notifyLockTaskModeChanged can only be called by system");
}
synchronized (this) {
@@ -6048,11 +6124,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
- long id = Binder.clearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
Settings.Global.putString(contentResolver, setting, value);
} finally {
- restoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
}
}
@@ -6077,11 +6153,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
"Permission denial: Profile owners cannot update %1$s", setting));
}
- long id = Binder.clearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
Settings.Secure.putStringForUser(contentResolver, setting, value, callingUserId);
} finally {
- restoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
}
}
@@ -6092,7 +6168,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
synchronized (this) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
int userId = UserHandle.getCallingUserId();
- long identity = Binder.clearCallingIdentity();
+ long identity = mInjector.binderClearCallingIdentity();
try {
IAudioService iAudioService = IAudioService.Stub.asInterface(
ServiceManager.getService(Context.AUDIO_SERVICE));
@@ -6100,7 +6176,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
} catch (RemoteException re) {
Slog.e(LOG_TAG, "Failed to setMasterMute", re);
} finally {
- Binder.restoreCallingIdentity(identity);
+ mInjector.binderRestoreCallingIdentity(identity);
}
}
}
@@ -6124,11 +6200,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
int userId = UserHandle.getCallingUserId();
- long id = Binder.clearCallingIdentity();
+ long id = mInjector.binderClearCallingIdentity();
try {
mUserManager.setUserIcon(userId, icon);
} finally {
- restoreCallingIdentity(id);
+ mInjector.binderRestoreCallingIdentity(id);
}
}
}
@@ -6142,7 +6218,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
final int userId = UserHandle.getCallingUserId();
LockPatternUtils utils = new LockPatternUtils(mContext);
- long ident = Binder.clearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
// disallow disabling the keyguard if a password is currently set
if (disabled && utils.isSecure(userId)) {
@@ -6150,7 +6226,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
utils.setLockScreenDisabled(disabled, userId);
} finally {
- Binder.restoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
return true;
}
@@ -6173,7 +6249,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
private boolean setStatusBarDisabledInternal(boolean disabled, int userId) {
- long ident = Binder.clearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
IStatusBarService statusBarService = IStatusBarService.Stub.asInterface(
ServiceManager.checkService(Context.STATUS_BAR_SERVICE));
@@ -6187,7 +6263,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
} catch (RemoteException e) {
Slog.e(LOG_TAG, "Failed to disable the status bar", e);
} finally {
- Binder.restoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
return false;
}
@@ -6394,8 +6470,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
mContext.enforceCallingOrSelfPermission(permission.NOTIFY_PENDING_SYSTEM_UPDATE,
"Only the system update service can broadcast update information");
- if (UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
- Slog.w(LOG_TAG, "Only the system update service in the primary user " +
+ if (UserHandle.getCallingUserId() != UserHandle.USER_SYSTEM) {
+ Slog.w(LOG_TAG, "Only the system update service in the system user " +
"can broadcast update information.");
return;
}
@@ -6418,7 +6494,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Log.e(LOG_TAG, "Cannot find device owner package", e);
}
if (receivers != null) {
- long ident = Binder.clearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
for (int i = 0; i < receivers.length; i++) {
if (permission.BIND_DEVICE_ADMIN.equals(receivers[i].permission)) {
@@ -6428,7 +6504,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
} finally {
- Binder.restoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
}
}
@@ -6459,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 = Binder.getCallingUserHandle();
+ UserHandle user = mInjector.binderGetCallingUserHandle();
synchronized (this) {
getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
- long ident = Binder.clearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
- final ApplicationInfo ai = AppGlobals.getPackageManager()
+ 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) {
@@ -6496,7 +6572,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
} catch (SecurityException se) {
return false;
} finally {
- Binder.restoreCallingIdentity(ident);
+ mInjector.binderRestoreCallingIdentity(ident);
}
}
}
@@ -6506,12 +6582,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
String permission) throws RemoteException {
PackageManager packageManager = mContext.getPackageManager();
- UserHandle user = Binder.getCallingUserHandle();
+ UserHandle user = mInjector.binderGetCallingUserHandle();
synchronized (this) {
getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
- long ident = Binder.clearCallingIdentity();
+ long ident = mInjector.binderClearCallingIdentity();
try {
- int granted = AppGlobals.getPackageManager().checkPermission(permission,
+ int granted = mIPackageManager.checkPermission(permission,
packageName, user.getIdentifier());
int permFlags = packageManager.getPermissionFlags(permission, packageName, user);
if ((permFlags & PackageManager.FLAG_PERMISSION_POLICY_FIXED)
@@ -6525,8 +6601,17 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
: DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED;
}
} finally {
- Binder.restoreCallingIdentity(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..a1690828a4df 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -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 aafaf8373cf8..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");
@@ -1327,4 +1332,4 @@ public final class SystemServer {
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, name);
Slog.i(TAG, name);
}
-}
+} \ No newline at end of file
diff --git a/services/midi/java/com/android/server/midi/MidiService.java b/services/midi/java/com/android/server/midi/MidiService.java
index f6de12dbf6cb..c6d5a7e268b7 100644
--- a/services/midi/java/com/android/server/midi/MidiService.java
+++ b/services/midi/java/com/android/server/midi/MidiService.java
@@ -588,6 +588,8 @@ public class MidiService extends IMidiManager.Stub {
Client client = getClient(token);
if (client == null) return;
client.addListener(listener);
+ // Let listener know whether any ports are already busy.
+ updateStickyDeviceStatus(client.mUid, listener);
}
@Override
@@ -597,6 +599,25 @@ public class MidiService extends IMidiManager.Stub {
client.removeListener(listener);
}
+ // Inform listener of the status of all known devices.
+ private void updateStickyDeviceStatus(int uid, IMidiDeviceListener listener) {
+ synchronized (mDevicesByInfo) {
+ for (Device device : mDevicesByInfo.values()) {
+ // ignore private devices that our client cannot access
+ if (device.isUidAllowed(uid)) {
+ try {
+ MidiDeviceStatus status = device.getDeviceStatus();
+ if (status != null) {
+ listener.onDeviceStatusChanged(status);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "remote exception", e);
+ }
+ }
+ }
+ }
+ }
+
private static final MidiDeviceInfo[] EMPTY_DEVICE_INFO_ARRAY = new MidiDeviceInfo[0];
public MidiDeviceInfo[] getDevices() {
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/core/java/android/net/IpReachabilityMonitor.java b/services/net/java/android/net/ip/IpReachabilityMonitor.java
index 88fb01437cd0..3acd56560f4a 100644
--- a/core/java/android/net/IpReachabilityMonitor.java
+++ b/services/net/java/android/net/ip/IpReachabilityMonitor.java
@@ -14,10 +14,11 @@
* limitations under the License.
*/
-package android.net;
+package android.net.ip;
import com.android.internal.annotations.GuardedBy;
+import android.content.Context;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.LinkProperties.ProvisioningChange;
@@ -31,6 +32,7 @@ import android.net.netlink.RtNetlinkNeighborMessage;
import android.net.netlink.StructNdaCacheInfo;
import android.net.netlink.StructNdMsg;
import android.net.netlink.StructNlMsgHdr;
+import android.os.PowerManager;
import android.os.SystemClock;
import android.system.ErrnoException;
import android.system.NetlinkSocketAddress;
@@ -74,6 +76,7 @@ public class IpReachabilityMonitor {
}
private final Object mLock = new Object();
+ private final PowerManager.WakeLock mWakeLock;
private final String mInterfaceName;
private final int mInterfaceIndex;
private final Callback mCallback;
@@ -136,7 +139,8 @@ public class IpReachabilityMonitor {
return returnValue;
}
- public IpReachabilityMonitor(String ifName, Callback callback) throws IllegalArgumentException {
+ public IpReachabilityMonitor(Context context, String ifName, Callback callback)
+ throws IllegalArgumentException {
mInterfaceName = ifName;
int ifIndex = -1;
try {
@@ -145,6 +149,8 @@ public class IpReachabilityMonitor {
} catch (SocketException | NullPointerException e) {
throw new IllegalArgumentException("invalid interface '" + ifName + "': ", e);
}
+ mWakeLock = ((PowerManager) context.getSystemService(Context.POWER_SERVICE)).newWakeLock(
+ PowerManager.PARTIAL_WAKE_LOCK, TAG + "." + mInterfaceName);
mCallback = callback;
mNetlinkSocketObserver = new NetlinkSocketObserver();
mObserverThread = new Thread(mNetlinkSocketObserver);
@@ -291,6 +297,17 @@ public class IpReachabilityMonitor {
synchronized (mLock) {
ipProbeList.addAll(mIpWatchList.keySet());
}
+
+ if (!ipProbeList.isEmpty() && stillRunning()) {
+ // Keep the CPU awake long enough to allow all ARP/ND
+ // probes a reasonable chance at success. See b/23197666.
+ //
+ // The wakelock we use is (by default) refcounted, and this version
+ // of acquire(timeout) queues a release message to keep acquisitions
+ // and releases balanced.
+ mWakeLock.acquire(getProbeWakeLockDuration());
+ }
+
for (InetAddress target : ipProbeList) {
if (!stillRunning()) {
break;
@@ -299,6 +316,22 @@ public class IpReachabilityMonitor {
}
}
+ private long getProbeWakeLockDuration() {
+ // Ideally, this would be computed by examining the values of:
+ //
+ // /proc/sys/net/ipv[46]/neigh/<ifname>/ucast_solicit
+ //
+ // and:
+ //
+ // /proc/sys/net/ipv[46]/neigh/<ifname>/retrans_time_ms
+ //
+ // For now, just make some assumptions.
+ final long numUnicastProbes = 3;
+ final long retransTimeMs = 1000;
+ final long gracePeriodMs = 500;
+ return (numUnicastProbes * retransTimeMs) + gracePeriodMs;
+ }
+
// TODO: simply the number of objects by making this extend Thread.
private final class NetlinkSocketObserver implements Runnable {
diff --git a/core/java/android/net/netlink/NetlinkConstants.java b/services/net/java/android/net/netlink/NetlinkConstants.java
index e331701efbce..e331701efbce 100644
--- a/core/java/android/net/netlink/NetlinkConstants.java
+++ b/services/net/java/android/net/netlink/NetlinkConstants.java
diff --git a/core/java/android/net/netlink/NetlinkErrorMessage.java b/services/net/java/android/net/netlink/NetlinkErrorMessage.java
index e2755740453a..e2755740453a 100644
--- a/core/java/android/net/netlink/NetlinkErrorMessage.java
+++ b/services/net/java/android/net/netlink/NetlinkErrorMessage.java
diff --git a/core/java/android/net/netlink/NetlinkMessage.java b/services/net/java/android/net/netlink/NetlinkMessage.java
index 3bf75cabea17..3bf75cabea17 100644
--- a/core/java/android/net/netlink/NetlinkMessage.java
+++ b/services/net/java/android/net/netlink/NetlinkMessage.java
diff --git a/core/java/android/net/netlink/NetlinkSocket.java b/services/net/java/android/net/netlink/NetlinkSocket.java
index 657d48c15250..657d48c15250 100644
--- a/core/java/android/net/netlink/NetlinkSocket.java
+++ b/services/net/java/android/net/netlink/NetlinkSocket.java
diff --git a/core/java/android/net/netlink/RtNetlinkNeighborMessage.java b/services/net/java/android/net/netlink/RtNetlinkNeighborMessage.java
index 02df1313c43f..02df1313c43f 100644
--- a/core/java/android/net/netlink/RtNetlinkNeighborMessage.java
+++ b/services/net/java/android/net/netlink/RtNetlinkNeighborMessage.java
diff --git a/core/java/android/net/netlink/StructNdMsg.java b/services/net/java/android/net/netlink/StructNdMsg.java
index b68ec0bc6226..b68ec0bc6226 100644
--- a/core/java/android/net/netlink/StructNdMsg.java
+++ b/services/net/java/android/net/netlink/StructNdMsg.java
diff --git a/core/java/android/net/netlink/StructNdaCacheInfo.java b/services/net/java/android/net/netlink/StructNdaCacheInfo.java
index 16cf56385eb8..16cf56385eb8 100644
--- a/core/java/android/net/netlink/StructNdaCacheInfo.java
+++ b/services/net/java/android/net/netlink/StructNdaCacheInfo.java
diff --git a/core/java/android/net/netlink/StructNlAttr.java b/services/net/java/android/net/netlink/StructNlAttr.java
index 597a6aa1c9eb..597a6aa1c9eb 100644
--- a/core/java/android/net/netlink/StructNlAttr.java
+++ b/services/net/java/android/net/netlink/StructNlAttr.java
diff --git a/core/java/android/net/netlink/StructNlMsgErr.java b/services/net/java/android/net/netlink/StructNlMsgErr.java
index f095af43c743..f095af43c743 100644
--- a/core/java/android/net/netlink/StructNlMsgErr.java
+++ b/services/net/java/android/net/netlink/StructNlMsgErr.java
diff --git a/core/java/android/net/netlink/StructNlMsgHdr.java b/services/net/java/android/net/netlink/StructNlMsgHdr.java
index 98ab5e719d69..98ab5e719d69 100644
--- a/core/java/android/net/netlink/StructNlMsgHdr.java
+++ b/services/net/java/android/net/netlink/StructNlMsgHdr.java
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 7d1282bceac9..c147bccc19b5 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -67,6 +67,33 @@
</intent-filter>
</receiver>
+ <receiver android:name="com.android.server.devicepolicy.DummyDeviceAdmins$Admin1"
+ android:permission="android.permission.BIND_DEVICE_ADMIN">
+ <meta-data android:name="android.app.device_admin"
+ android:resource="@xml/device_admin_sample" />
+ <intent-filter>
+ <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
+ </intent-filter>
+ </receiver>
+
+ <receiver android:name="com.android.server.devicepolicy.DummyDeviceAdmins$Admin2"
+ android:permission="android.permission.BIND_DEVICE_ADMIN">
+ <meta-data android:name="android.app.device_admin"
+ android:resource="@xml/device_admin_sample" />
+ <intent-filter>
+ <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
+ </intent-filter>
+ </receiver>
+
+ <receiver android:name="com.android.server.devicepolicy.DummyDeviceAdmins$Admin3"
+ android:permission="android.permission.BIND_DEVICE_ADMIN">
+ <meta-data android:name="android.app.device_admin"
+ android:resource="@xml/device_admin_sample" />
+ <intent-filter>
+ <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
+ </intent-filter>
+ </receiver>
+
</application>
<instrumentation
diff --git a/core/tests/coretests/src/android/net/netlink/NetlinkErrorMessageTest.java b/services/tests/servicestests/src/android/net/netlink/NetlinkErrorMessageTest.java
index e677475f5907..e677475f5907 100644
--- a/core/tests/coretests/src/android/net/netlink/NetlinkErrorMessageTest.java
+++ b/services/tests/servicestests/src/android/net/netlink/NetlinkErrorMessageTest.java
diff --git a/core/tests/coretests/src/android/net/netlink/NetlinkSocketTest.java b/services/tests/servicestests/src/android/net/netlink/NetlinkSocketTest.java
index c599fe3e5b76..c599fe3e5b76 100644
--- a/core/tests/coretests/src/android/net/netlink/NetlinkSocketTest.java
+++ b/services/tests/servicestests/src/android/net/netlink/NetlinkSocketTest.java
diff --git a/core/tests/coretests/src/android/net/netlink/RtNetlinkNeighborMessageTest.java b/services/tests/servicestests/src/android/net/netlink/RtNetlinkNeighborMessageTest.java
index 19ee00036b61..19ee00036b61 100644
--- a/core/tests/coretests/src/android/net/netlink/RtNetlinkNeighborMessageTest.java
+++ b/services/tests/servicestests/src/android/net/netlink/RtNetlinkNeighborMessageTest.java
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
new file mode 100644
index 000000000000..c6c74979f6ef
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -0,0 +1,241 @@
+/*
+ * 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.devicepolicy;
+
+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.media.IAudioService;
+import android.os.Looper;
+import android.os.PowerManagerInternal;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.view.IWindowManager;
+
+import java.io.File;
+
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.when;
+
+/**
+ * Overrides {@link #DevicePolicyManagerService} for dependency injection.
+ */
+public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerService {
+ /**
+ * Overrides {@link #Owners} for dependency injection.
+ */
+ public static class OwnersTestable extends Owners {
+ public static final String LEGACY_FILE = "legacy.xml";
+ public static final String DEVICE_OWNER_FILE = "device_owner2.xml";
+ public static final String PROFILE_OWNER_FILE_BASE = "profile_owner.xml";
+
+ private final File mLegacyFile;
+ private final File mDeviceOwnerFile;
+ private final File mProfileOwnerBase;
+
+ public OwnersTestable(Context context, File dataDir) {
+ super(context);
+ mLegacyFile = new File(dataDir, LEGACY_FILE);
+ mDeviceOwnerFile = new File(dataDir, DEVICE_OWNER_FILE);
+ mProfileOwnerBase = new File(dataDir, PROFILE_OWNER_FILE_BASE);
+ }
+
+ @Override
+ File getLegacyConfigFileWithTestOverride() {
+ return mLegacyFile;
+ }
+
+ @Override
+ File getDeviceOwnerFileWithTestOverride() {
+ return mDeviceOwnerFile;
+ }
+
+ @Override
+ File getProfileOwnerFileWithTestOverride(int userId) {
+ return new File(mDeviceOwnerFile.getAbsoluteFile() + "-" + userId);
+ }
+ }
+
+ public final DpmMockContext context;
+
+ public DevicePolicyManagerServiceTestable(DpmMockContext context, File dataDir) {
+ this(new MockInjector(context, dataDir));
+ }
+
+ private DevicePolicyManagerServiceTestable(MockInjector injector) {
+ super(injector);
+ this.context = injector.context;
+ }
+
+ private static class MockInjector extends Injector {
+
+ public final DpmMockContext context;
+
+ public final File dataDir;
+
+ public final File systemUserDataDir;
+ public final File secondUserDataDir;
+
+ private MockInjector(DpmMockContext context, File dataDir) {
+ super(context);
+ this.context = context;
+ this.dataDir = dataDir;
+
+ systemUserDataDir = new File(dataDir, "user0");
+ DpmTestUtils.clearDir(dataDir);
+
+ secondUserDataDir = new File(dataDir, "user" + DpmMockContext.CALLER_USER_HANDLE);
+ DpmTestUtils.clearDir(secondUserDataDir);
+
+ when(context.environment.getUserSystemDirectory(
+ eq(DpmMockContext.CALLER_USER_HANDLE))).thenReturn(secondUserDataDir);
+ }
+
+ @Override
+ Owners newOwners() {
+ return new OwnersTestable(context, dataDir);
+ }
+
+ @Override
+ UserManager getUserManager() {
+ return context.userManager;
+ }
+
+ @Override
+ PowerManagerInternal getPowerManagerInternal() {
+ return context.powerManagerInternal;
+ }
+
+ @Override
+ NotificationManager getNotificationManager() {
+ return context.notificationManager;
+ }
+
+ @Override
+ IWindowManager getIWindowManager() {
+ return context.iwindowManager;
+ }
+
+ @Override
+ IActivityManager getIActivityManager() {
+ return context.iactivityManager;
+ }
+
+ @Override
+ IPackageManager getIPackageManager() {
+ return context.ipackageManager;
+ }
+
+ @Override
+ IBackupManager getIBackupManager() {
+ return context.ibackupManager;
+ }
+
+ @Override
+ IAudioService getIAudioService() {
+ return context.iaudioService;
+ }
+
+ @Override
+ Looper getMyLooper() {
+ return Looper.getMainLooper();
+ }
+
+ @Override
+ LockPatternUtils newLockPatternUtils() {
+ return context.lockPatternUtils;
+ }
+
+ @Override
+ String getDevicePolicyFilePathForSystemUser() {
+ return systemUserDataDir.getAbsolutePath();
+ }
+
+ @Override
+ long binderClearCallingIdentity() {
+ return context.binder.clearCallingIdentity();
+ }
+
+ @Override
+ void binderRestoreCallingIdentity(long token) {
+ context.binder.restoreCallingIdentity(token);
+ }
+
+ @Override
+ int binderGetCallingUid() {
+ return context.binder.getCallingUid();
+ }
+
+ @Override
+ int binderGetCallingPid() {
+ return context.binder.getCallingPid();
+ }
+
+ @Override
+ UserHandle binderGetCallingUserHandle() {
+ return context.binder.getCallingUserHandle();
+ }
+
+ @Override
+ boolean binderIsCallingUidMyUid() {
+ return context.binder.isCallerUidMyUid();
+ }
+
+ @Override
+ File environmentGetUserSystemDirectory(int userId) {
+ return context.environment.getUserSystemDirectory(userId);
+ }
+
+ @Override
+ void powerManagerGoToSleep(long time, int reason, int flags) {
+ context.powerManager.goToSleep(time, reason, flags);
+ }
+
+ @Override
+ boolean systemPropertiesGetBoolean(String key, boolean def) {
+ return context.systemProperties.getBoolean(key, def);
+ }
+
+ @Override
+ long systemPropertiesGetLong(String key, long def) {
+ return context.systemProperties.getLong(key, def);
+ }
+
+ @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
new file mode 100644
index 000000000000..0072f526bd95
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -0,0 +1,592 @@
+/*
+ * 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.devicepolicy;
+
+import com.android.server.LocalServices;
+
+import android.Manifest.permission;
+import android.app.Activity;
+import android.app.admin.DeviceAdminReceiver;
+import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyManagerInternal;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+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;
+import static org.mockito.Mockito.when;
+
+/**
+ * Tests for DevicePolicyManager( and DevicePolicyManagerService).
+ *
+ m FrameworksServicesTests &&
+ adb install \
+ -r out/target/product/hammerhead/data/app/FrameworksServicesTests/FrameworksServicesTests.apk &&
+ adb shell am instrument -e class com.android.server.devicepolicy.DevicePolicyManagerTest \
+ -w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
+
+ (mmma frameworks/base/services/tests/servicestests/ for non-ninja build)
+ */
+public class DevicePolicyManagerTest extends DpmTestBase {
+
+
+ private DpmMockContext mContext;
+ public DevicePolicyManager dpm;
+ public DevicePolicyManagerServiceTestable dpms;
+ public ComponentName admin1;
+ public ComponentName admin2;
+ public ComponentName admin3;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mContext = getContext();
+
+ when(mContext.packageManager.hasSystemFeature(eq(PackageManager.FEATURE_DEVICE_ADMIN)))
+ .thenReturn(true);
+
+ LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
+ dpms = new DevicePolicyManagerServiceTestable(mContext, dataDir);
+ dpm = new DevicePolicyManagerTestable(mContext, dpms);
+
+ admin1 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin1.class);
+ admin2 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin2.class);
+ admin3 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin3.class);
+
+ setUpPackageManagerForAdmin(admin1);
+ setUpPackageManagerForAdmin(admin2);
+ setUpPackageManagerForAdmin(admin3);
+
+ setUpApplicationInfo(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED);
+ setUpPackageInfo();
+ setUpUserManager();
+ }
+
+ /**
+ * Set up a mock result for {@link PackageManager#queryBroadcastReceivers}. We'll return
+ * 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) {
+ final Intent resolveIntent = new Intent();
+ resolveIntent.setComponent(admin);
+ final List<ResolveInfo> realResolveInfo =
+ mRealTestContext.getPackageManager().queryBroadcastReceivers(
+ resolveIntent,
+ PackageManager.GET_META_DATA);
+ assertNotNull(realResolveInfo);
+ assertEquals(1, realResolveInfo.size());
+
+ // We need to rewrite the UID in the activity info.
+ realResolveInfo.get(0).activityInfo.applicationInfo.uid = DpmMockContext.CALLER_UID;
+
+ 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)
+ );
+ }
+
+ /**
+ * 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);
+
+ ai.enabledSetting = enabledSetting;
+
+ doReturn(ai).when(mContext.ipackageManager).getApplicationInfo(
+ eq(admin1.getPackageName()),
+ eq(PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS),
+ eq(DpmMockContext.CALLER_USER_HANDLE));
+ }
+
+ /**
+ * 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));
+
+ // System user is always running.
+ when(mContext.userManager.isUserRunning(MockUtils.checkUserHandle(UserHandle.USER_SYSTEM)))
+ .thenReturn(true);
+
+ // Set up (default) UserInfo for CALLER_USER_HANDLE.
+ final UserInfo uh = new UserInfo(DpmMockContext.CALLER_USER_HANDLE,
+ "user" + DpmMockContext.CALLER_USER_HANDLE, 0);
+
+ when(mContext.userManager.getUserInfo(eq(DpmMockContext.CALLER_USER_HANDLE)))
+ .thenReturn(uh);
+ }
+
+ 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);
+
+ LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
+ new DevicePolicyManagerServiceTestable(mContext, dataDir);
+
+ // If the device has no DPMS feature, it shouldn't register the local service.
+ assertNull(LocalServices.getService(DevicePolicyManagerInternal.class));
+ }
+
+ /**
+ * Caller doesn't have proper permissions.
+ */
+ public void testSetActiveAdmin_SecurityException() {
+ // 1. Failure cases.
+
+ // Caller doesn't have MANAGE_DEVICE_ADMINS.
+ try {
+ dpm.setActiveAdmin(admin1, false);
+ fail("Didn't throw SecurityException");
+ } catch (SecurityException expected) {
+ }
+
+ // Caller has MANAGE_DEVICE_ADMINS, but for different user.
+ mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
+ try {
+ dpm.setActiveAdmin(admin1, false, DpmMockContext.CALLER_USER_HANDLE + 1);
+ fail("Didn't throw SecurityException");
+ } catch (SecurityException expected) {
+ }
+ }
+
+ /**
+ * Test for:
+ * {@link DevicePolicyManager#setActiveAdmin}
+ * with replace=false and replace=true
+ * {@link DevicePolicyManager#isAdminActive}
+ * {@link DevicePolicyManager#isAdminActiveAsUser}
+ * {@link DevicePolicyManager#getActiveAdmins}
+ * {@link DevicePolicyManager#getActiveAdminsAsUser}
+ */
+ public void testSetActiveAdmin() throws Exception {
+ // 1. Make sure the caller has proper permissions.
+ mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
+
+ // 2. Call the API.
+ dpm.setActiveAdmin(admin1, /* replace =*/ false);
+
+ // 3. Verify internal calls.
+
+ // Check if the boradcast is sent.
+ verify(mContext.spiedContext).sendBroadcastAsUser(
+ MockUtils.checkIntentAction(
+ DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
+ MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE));
+ verify(mContext.spiedContext).sendBroadcastAsUser(
+ MockUtils.checkIntentAction(
+ DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED),
+ MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE));
+
+ verify(mContext.ipackageManager, times(1)).setApplicationEnabledSetting(
+ eq(admin1.getPackageName()),
+ eq(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT),
+ eq(PackageManager.DONT_KILL_APP),
+ eq(DpmMockContext.CALLER_USER_HANDLE),
+ anyString());
+
+ // TODO Verify other calls too.
+
+ // Make sure it's active admin1.
+ assertTrue(dpm.isAdminActive(admin1));
+ assertFalse(dpm.isAdminActive(admin2));
+ assertFalse(dpm.isAdminActive(admin3));
+
+ // But not admin1 for a different user.
+
+ // For this to work, caller needs android.permission.INTERACT_ACROSS_USERS_FULL.
+ // (Because we're checking a different user's status from CALLER_USER_HANDLE.)
+ mContext.callerPermissions.add("android.permission.INTERACT_ACROSS_USERS_FULL");
+
+ assertFalse(dpm.isAdminActiveAsUser(admin1, DpmMockContext.CALLER_USER_HANDLE + 1));
+ assertFalse(dpm.isAdminActiveAsUser(admin2, DpmMockContext.CALLER_USER_HANDLE + 1));
+
+ mContext.callerPermissions.remove("android.permission.INTERACT_ACROSS_USERS_FULL");
+
+ // Next, add one more admin.
+ // Before doing so, update the application info, now it's enabled.
+ setUpApplicationInfo(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
+
+ dpm.setActiveAdmin(admin2, /* replace =*/ false);
+
+ // Now we have two admins.
+ assertTrue(dpm.isAdminActive(admin1));
+ assertTrue(dpm.isAdminActive(admin2));
+ assertFalse(dpm.isAdminActive(admin3));
+
+ // Admin2 was already enabled, so setApplicationEnabledSetting() shouldn't have called
+ // again. (times(1) because it was previously called for admin1)
+ verify(mContext.ipackageManager, times(1)).setApplicationEnabledSetting(
+ eq(admin1.getPackageName()),
+ eq(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT),
+ eq(PackageManager.DONT_KILL_APP),
+ eq(DpmMockContext.CALLER_USER_HANDLE),
+ anyString());
+
+ // 4. Add the same admin1 again without replace, which should throw.
+ try {
+ dpm.setActiveAdmin(admin1, /* replace =*/ false);
+ fail("Didn't throw");
+ } catch (IllegalArgumentException expected) {
+ }
+
+ // 5. Add the same admin1 again with replace, which should succeed.
+ dpm.setActiveAdmin(admin1, /* replace =*/ true);
+
+ // TODO make sure it's replaced.
+
+ // 6. Test getActiveAdmins()
+ List<ComponentName> admins = dpm.getActiveAdmins();
+ assertEquals(2, admins.size());
+ assertEquals(admin1, admins.get(0));
+ assertEquals(admin2, admins.get(1));
+
+ // Another user has no admins.
+ mContext.callerPermissions.add("android.permission.INTERACT_ACROSS_USERS_FULL");
+
+ assertEquals(0, DpmTestUtils.getListSizeAllowingNull(
+ dpm.getActiveAdminsAsUser(DpmMockContext.CALLER_USER_HANDLE + 1)));
+
+ mContext.callerPermissions.remove("android.permission.INTERACT_ACROSS_USERS_FULL");
+ }
+
+ /**
+ * Test for:
+ * {@link DevicePolicyManager#setActiveAdmin}
+ * with replace=false
+ */
+ public void testSetActiveAdmin_twiceWithoutReplace() throws Exception {
+ // 1. Make sure the caller has proper permissions.
+ mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
+
+ dpm.setActiveAdmin(admin1, /* replace =*/ false);
+ assertTrue(dpm.isAdminActive(admin1));
+
+ // Add the same admin1 again without replace, which should throw.
+ try {
+ dpm.setActiveAdmin(admin1, /* replace =*/ false);
+ fail("Didn't throw");
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ /**
+ * Test for:
+ * {@link DevicePolicyManager#removeActiveAdmin}
+ */
+ public void testRemoveActiveAdmin_SecurityException() {
+ mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
+
+ // Add admin.
+
+ dpm.setActiveAdmin(admin1, /* replace =*/ false);
+
+ assertTrue(dpm.isAdminActive(admin1));
+
+ assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
+
+ // Directly call the DPMS method with a different userid, which should fail.
+ try {
+ dpms.removeActiveAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE + 1);
+ fail("Didn't throw SecurityException");
+ } catch (SecurityException expected) {
+ }
+
+ // Try to remove active admin with a different caller userid should fail too, without
+ // having MANAGE_DEVICE_ADMINS.
+ mContext.callerPermissions.clear();
+
+ mContext.binder.callingUid = 1234567;
+ try {
+ dpm.removeActiveAdmin(admin1);
+ fail("Didn't throw SecurityException");
+ } catch (SecurityException expected) {
+ }
+ }
+
+ /**
+ * Test for:
+ * {@link DevicePolicyManager#removeActiveAdmin}
+ */
+ public void testRemoveActiveAdmin_fromDifferentUserWithMINTERACT_ACROSS_USERS_FULL() {
+ mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
+
+ // Add admin1.
+
+ dpm.setActiveAdmin(admin1, /* replace =*/ false);
+
+ assertTrue(dpm.isAdminActive(admin1));
+ assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
+
+ // Different user, but should work, because caller has proper permissions.
+ mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
+ mContext.binder.callingUid = 1234567;
+ dpm.removeActiveAdmin(admin1);
+
+ assertTrue(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
+
+ // TODO DO Still can't be removed in this case.
+ }
+
+ /**
+ * Test for:
+ * {@link DevicePolicyManager#removeActiveAdmin}
+ */
+ public void testRemoveActiveAdmin_sameUserNoMANAGE_DEVICE_ADMINS() {
+ // Need MANAGE_DEVICE_ADMINS for setActiveAdmin. We'll remove it later.
+ mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
+
+ // Add admin1.
+
+ dpm.setActiveAdmin(admin1, /* replace =*/ false);
+
+ assertTrue(dpm.isAdminActive(admin1));
+ assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
+
+ // Broadcast from saveSettingsLocked().
+ verify(mContext.spiedContext, times(1)).sendBroadcastAsUser(
+ MockUtils.checkIntentAction(
+ DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
+ MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE));
+
+ // Remove. No permissions, but same user, so it'll work.
+ mContext.callerPermissions.clear();
+ dpm.removeActiveAdmin(admin1);
+
+ final ArgumentCaptor<BroadcastReceiver> brCap =
+ ArgumentCaptor.forClass(BroadcastReceiver.class);
+
+ // Is removing now, but not removed yet.
+ assertTrue(dpm.isAdminActive(admin1));
+ assertTrue(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
+
+ verify(mContext.spiedContext).sendOrderedBroadcastAsUser(
+ MockUtils.checkIntentAction(
+ DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED),
+ MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE),
+ isNull(String.class),
+ brCap.capture(),
+ eq(dpms.mHandler),
+ eq(Activity.RESULT_OK),
+ isNull(String.class),
+ isNull(Bundle.class));
+
+ brCap.getValue().onReceive(mContext, null);
+
+ assertFalse(dpm.isAdminActive(admin1));
+ assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
+
+ // Again broadcast from saveSettingsLocked().
+ verify(mContext.spiedContext, times(2)).sendBroadcastAsUser(
+ MockUtils.checkIntentAction(
+ DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
+ MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE));
+
+ // 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);
+
+ // Call from a process on the system user.
+ mContext.binder.callingUid = 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;
+
+ // DO needs to be an DA.
+ dpm.setActiveAdmin(admin1, /* replace =*/ false);
+ 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
new file mode 100644
index 000000000000..325bf9ff0225
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTestable.java
@@ -0,0 +1,36 @@
+/*
+ * 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.devicepolicy;
+
+import android.app.admin.DevicePolicyManager;
+
+/**
+ * Overrides {@link #DevicePolicyManager} for dependency injection.
+ */
+public class DevicePolicyManagerTestable extends DevicePolicyManager {
+ public final DevicePolicyManagerServiceTestable dpms;
+
+ public DevicePolicyManagerTestable(DpmMockContext context,
+ DevicePolicyManagerServiceTestable dpms) {
+ super(context, dpms);
+ this.dpms = dpms;
+ }
+
+ @Override
+ public int myUserId() {
+ return DpmMockContext.CALLER_USER_HANDLE;
+ }
+}
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 c2b89819501b..f3d91600251e 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -16,31 +16,382 @@
package com.android.server.devicepolicy;
+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.ContextWrapper;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
+import android.media.IAudioService;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.PowerManager.WakeLock;
+import android.os.PowerManagerInternal;
+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.Mockito.mock;
+import static org.mockito.Mockito.spy;
-public class DpmMockContext extends ContextWrapper {
- private final UserManager mMockUserManager;
+/**
+ * Context used throughout DPMS tests.
+ */
+public class DpmMockContext extends MockContext {
+ /**
+ * User-id of a non-system user we use throughout unit tests.
+ */
+ public static final int CALLER_USER_HANDLE = 20;
+ /**
+ * UID corresponding to {@link #CALLER_USER_HANDLE}.
+ */
+ public static final int CALLER_UID = UserHandle.PER_USER_RANGE * CALLER_USER_HANDLE + 123;
- public DpmMockContext(Context context) {
- super(context);
- mMockUserManager = mock(UserManager.class);
+ /**
+ * UID used when a caller is on the system user.
+ */
+ public static final int CALLER_SYSTEM_USER_UID = 123;
+
+ /**
+ * PID of the caller.
+ */
+ public static final int CALLER_PID = 22222;
+
+ /**
+ * UID of the system server.
+ */
+ public static final int SYSTEM_UID = android.os.Process.SYSTEM_UID;
+
+ /**
+ * PID of the system server.
+ */
+ public static final int SYSTEM_PID = 11111;
+
+ public static class MockBinder {
+ public int callingUid = CALLER_UID;
+ public int callingPid = CALLER_PID;
+
+ public long clearCallingIdentity() {
+ final long token = (((long) callingUid) << 32) | (callingPid);
+ callingUid = SYSTEM_UID;
+ callingPid = SYSTEM_PID;
+ return token;
+ }
+
+ public void restoreCallingIdentity(long token) {
+ callingUid = (int) (token >> 32);
+ callingPid = (int) token;
+ }
+
+ public int getCallingUid() {
+ return callingUid;
+ }
+
+ public int getCallingPid() {
+ return callingPid;
+ }
+
+ public UserHandle getCallingUserHandle() {
+ return new UserHandle(UserHandle.getUserId(getCallingUid()));
+ }
+
+ public boolean isCallerUidMyUid() {
+ return callingUid == SYSTEM_UID;
+ }
+ }
+
+ public static class EnvironmentForMock {
+ public File getUserSystemDirectory(int userId) {
+ return null;
+ }
+ }
+
+ public static class PowerManagerForMock {
+ public WakeLock newWakeLock(int levelAndFlags, String tag) {
+ return null;
+ }
+
+ public void goToSleep(long time, int reason, int flags) {
+ }
+ }
+
+ public static class SystemPropertiesForMock {
+ public boolean getBoolean(String key, boolean def) {
+ return false;
+ }
+
+ public long getLong(String key, long def) {
+ return 0;
+ }
+
+ public String get(String key, String def) {
+ return null;
+ }
+
+ public String get(String key) {
+ return null;
+ }
+
+ public void set(String key, String value) {
+ }
+ }
+
+ public static class UserManagerForMock {
+ public boolean isSplitSystemUser() {
+ return false;
+ }
}
- public UserManager getMockUserManager() {
- return mMockUserManager;
+ public final Context realTestContext;
+
+ /**
+ * Use this instance to verify unimplemented methods such as {@link #sendBroadcast}.
+ * (Spying on {@code this} instance will confuse mockito somehow and I got weired "wrong number
+ * of arguments" exceptions.)
+ */
+ public final Context spiedContext;
+
+ 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. */
+ public final PackageManager packageManager;
+
+ public final List<String> callerPermissions = new ArrayList<>();
+
+ public DpmMockContext(Context context) {
+ realTestContext = context;
+ 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);
}
@Override
public Object getSystemService(String name) {
switch (name) {
case Context.USER_SERVICE:
- return mMockUserManager;
+ return userManager;
+ case Context.POWER_SERVICE:
+ return powerManager;
+ }
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public PackageManager getPackageManager() {
+ return packageManager;
+ }
+
+ @Override
+ public void enforceCallingOrSelfPermission(String permission, String message) {
+ if (binder.getCallingUid() == SYSTEM_UID) {
+ return; // Assume system has all permissions.
+ }
+ if (!callerPermissions.contains(permission)) {
+ throw new SecurityException("Caller doesn't have " + permission + " : " + message);
+ }
+ }
+
+ @Override
+ public void sendBroadcast(Intent intent) {
+ spiedContext.sendBroadcast(intent);
+ }
+
+ @Override
+ public void sendBroadcast(Intent intent, String receiverPermission) {
+ spiedContext.sendBroadcast(intent, receiverPermission);
+ }
+
+ @Override
+ public void sendBroadcastMultiplePermissions(Intent intent, String[] receiverPermissions) {
+ spiedContext.sendBroadcastMultiplePermissions(intent, receiverPermissions);
+ }
+
+ @Override
+ public void sendBroadcast(Intent intent, String receiverPermission, Bundle options) {
+ spiedContext.sendBroadcast(intent, receiverPermission, options);
+ }
+
+ @Override
+ public void sendBroadcast(Intent intent, String receiverPermission, int appOp) {
+ spiedContext.sendBroadcast(intent, receiverPermission, appOp);
+ }
+
+ @Override
+ public void sendOrderedBroadcast(Intent intent, String receiverPermission) {
+ spiedContext.sendOrderedBroadcast(intent, receiverPermission);
+ }
+
+ @Override
+ public void sendOrderedBroadcast(Intent intent, String receiverPermission,
+ BroadcastReceiver resultReceiver, Handler scheduler, int initialCode,
+ String initialData, Bundle initialExtras) {
+ spiedContext.sendOrderedBroadcast(intent, receiverPermission, resultReceiver, scheduler,
+ initialCode, initialData, initialExtras);
+ }
+
+ @Override
+ public void sendOrderedBroadcast(Intent intent, String receiverPermission, Bundle options,
+ BroadcastReceiver resultReceiver, Handler scheduler, int initialCode,
+ String initialData, Bundle initialExtras) {
+ spiedContext.sendOrderedBroadcast(intent, receiverPermission, options, resultReceiver,
+ scheduler,
+ initialCode, initialData, initialExtras);
+ }
+
+ @Override
+ public void sendOrderedBroadcast(Intent intent, String receiverPermission, int appOp,
+ BroadcastReceiver resultReceiver, Handler scheduler, int initialCode,
+ String initialData, Bundle initialExtras) {
+ spiedContext.sendOrderedBroadcast(intent, receiverPermission, appOp, resultReceiver,
+ scheduler,
+ initialCode, initialData, initialExtras);
+ }
+
+ @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());
}
- return super.getSystemService(name);
+
+ spiedContext.sendBroadcastAsUser(intent, user);
+ }
+
+ @Override
+ public void sendBroadcastAsUser(Intent intent, UserHandle user, String receiverPermission) {
+ spiedContext.sendBroadcastAsUser(intent, user, receiverPermission);
+ }
+
+ @Override
+ public void sendBroadcastAsUser(Intent intent, UserHandle user, String receiverPermission,
+ int appOp) {
+ spiedContext.sendBroadcastAsUser(intent, user, receiverPermission, appOp);
+ }
+
+ @Override
+ public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
+ String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler,
+ int initialCode, String initialData, Bundle initialExtras) {
+ spiedContext.sendOrderedBroadcastAsUser(intent, user, receiverPermission, resultReceiver,
+ scheduler, initialCode, initialData, initialExtras);
+ }
+
+ @Override
+ public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
+ String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
+ Handler scheduler, int initialCode, String initialData, Bundle initialExtras) {
+ spiedContext.sendOrderedBroadcastAsUser(intent, user, receiverPermission, appOp,
+ resultReceiver,
+ scheduler, initialCode, initialData, initialExtras);
+ }
+
+ @Override
+ public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
+ String receiverPermission, int appOp, Bundle options, BroadcastReceiver resultReceiver,
+ Handler scheduler, int initialCode, String initialData, Bundle initialExtras) {
+ spiedContext.sendOrderedBroadcastAsUser(intent, user, receiverPermission, appOp, options,
+ resultReceiver, scheduler, initialCode, initialData, initialExtras);
+ }
+
+ @Override
+ public void sendStickyBroadcast(Intent intent) {
+ spiedContext.sendStickyBroadcast(intent);
+ }
+
+ @Override
+ public void sendStickyOrderedBroadcast(Intent intent, BroadcastReceiver resultReceiver,
+ Handler scheduler, int initialCode, String initialData, Bundle initialExtras) {
+ spiedContext.sendStickyOrderedBroadcast(intent, resultReceiver, scheduler, initialCode,
+ initialData, initialExtras);
+ }
+
+ @Override
+ public void removeStickyBroadcast(Intent intent) {
+ spiedContext.removeStickyBroadcast(intent);
+ }
+
+ @Override
+ public void sendStickyBroadcastAsUser(Intent intent, UserHandle user) {
+ spiedContext.sendStickyBroadcastAsUser(intent, user);
+ }
+
+ @Override
+ public void sendStickyOrderedBroadcastAsUser(Intent intent, UserHandle user,
+ BroadcastReceiver resultReceiver, Handler scheduler, int initialCode,
+ String initialData, Bundle initialExtras) {
+ spiedContext.sendStickyOrderedBroadcastAsUser(intent, user, resultReceiver, scheduler, initialCode,
+ initialData, initialExtras);
+ }
+
+ @Override
+ public void removeStickyBroadcastAsUser(Intent intent, UserHandle user) {
+ spiedContext.removeStickyBroadcastAsUser(intent, user);
+ }
+
+ @Override
+ public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
+ return spiedContext.registerReceiver(receiver, filter);
+ }
+
+ @Override
+ public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
+ String broadcastPermission, Handler scheduler) {
+ return spiedContext.registerReceiver(receiver, filter, broadcastPermission, scheduler);
+ }
+
+ @Override
+ public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
+ IntentFilter filter, String broadcastPermission, Handler scheduler) {
+ return spiedContext.registerReceiverAsUser(receiver, user, filter, broadcastPermission,
+ scheduler);
+ }
+
+ @Override
+ public void unregisterReceiver(BroadcastReceiver receiver) {
+ spiedContext.unregisterReceiver(receiver);
}
}
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 445260b9da6c..6f9f6ab7c5b9 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
@@ -19,14 +19,25 @@ package com.android.server.devicepolicy;
import android.content.Context;
import android.test.AndroidTestCase;
-public class DpmTestBase extends AndroidTestCase {
- private DpmMockContext mMockContext;
+import java.io.File;
+
+public abstract class DpmTestBase extends AndroidTestCase {
+ public static final String TAG = "DpmTest";
+
+ protected Context mRealTestContext;
+ protected DpmMockContext mMockContext;
+
+ public File dataDir;
@Override
protected void setUp() throws Exception {
super.setUp();
+ mRealTestContext = super.getContext();
mMockContext = new DpmMockContext(super.getContext());
+
+ dataDir = new File(mRealTestContext.getCacheDir(), "test-data");
+ DpmTestUtils.clearDir(dataDir);
}
@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
new file mode 100644
index 000000000000..44a851abe476
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.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.server.devicepolicy;
+
+import android.os.FileUtils;
+import android.util.Log;
+import android.util.Printer;
+
+import org.junit.Assert;
+
+import java.io.File;
+import java.util.List;
+
+public class DpmTestUtils {
+ private DpmTestUtils() {
+ }
+
+ public static void clearDir(File dir) {
+ if (dir.exists()) {
+ Assert.assertTrue("failed to delete dir", FileUtils.deleteContents(dir));
+ }
+ dir.mkdirs();
+ Log.i(DpmTestBase.TAG, "Created " + dir);
+ }
+
+ public static int getListSizeAllowingNull(List<?> list) {
+ return list == null ? 0 : list.size();
+ }
+
+ public static Printer LOG_PRINTER = new Printer() {
+ @Override
+ public void println(String x) {
+ Log.i(DpmTestBase.TAG, 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
new file mode 100644
index 000000000000..08293a259145
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmins.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.server.devicepolicy;
+
+import android.app.admin.DeviceAdminReceiver;
+
+public class DummyDeviceAdmins {
+ public static class Admin1 extends DeviceAdminReceiver {
+ }
+ public static class Admin2 extends DeviceAdminReceiver {
+ }
+ public static class Admin3 extends DeviceAdminReceiver {
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java
new file mode 100644
index 000000000000..5008fbfa3b10
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java
@@ -0,0 +1,80 @@
+/*
+ * 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.devicepolicy;
+
+import com.google.common.base.Objects;
+
+import android.content.ComponentName;
+import android.content.Intent;
+import android.os.UserHandle;
+
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.mockito.Mockito;
+
+public class MockUtils {
+ private MockUtils() {
+ }
+
+ public static UserHandle checkUserHandle(final int userId) {
+ final Matcher<UserHandle> m = new BaseMatcher<UserHandle>() {
+ @Override
+ public boolean matches(Object item) {
+ if (item == null) return false;
+ return Objects.equal(((UserHandle) item).getIdentifier(), userId);
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("UserHandle: user-id= \"" + userId + "\"");
+ }
+ };
+ return Mockito.argThat(m);
+ }
+
+ public static Intent checkIntentComponent(final ComponentName component) {
+ final Matcher<Intent> m = new BaseMatcher<Intent>() {
+ @Override
+ public boolean matches(Object item) {
+ if (item == null) return false;
+ return Objects.equal(((Intent) item).getComponent(), component);
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("Intent: component=\"" + component + "\"");
+ }
+ };
+ return Mockito.argThat(m);
+ }
+
+ public static Intent checkIntentAction(final String action) {
+ final Matcher<Intent> m = new BaseMatcher<Intent>() {
+ @Override
+ public boolean matches(Object item) {
+ if (item == null) return false;
+ return Objects.equal(((Intent) item).getAction(), action);
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("Intent: action=\"" + action + "\"");
+ }
+ };
+ return Mockito.argThat(m);
+ }
+}
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 3b88fb165775..a07d61520fa4 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java
@@ -16,12 +16,11 @@
package com.android.server.devicepolicy;
+import com.android.server.devicepolicy.DevicePolicyManagerServiceTestable.OwnersTestable;
+
import android.content.ComponentName;
-import android.content.Context;
import android.content.pm.UserInfo;
-import android.os.FileUtils;
import android.os.UserHandle;
-import android.test.AndroidTestCase;
import android.util.Log;
import java.io.BufferedReader;
@@ -31,8 +30,6 @@ import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
-import junit.framework.Assert;
-
import static org.mockito.Mockito.when;
/**
@@ -47,58 +44,11 @@ import static org.mockito.Mockito.when;
(mmma frameworks/base/services/tests/servicestests/ for non-ninja build)
*/
public class OwnersTest extends DpmTestBase {
- private static final String TAG = "DeviceOwnerTest";
-
- private static final String LEGACY_FILE = "legacy.xml";
- private static final String DEVICE_OWNER_FILE = "device_owner2.xml";
- private static final String PROFILE_OWNER_FILE_BASE = "profile_owner.xml";
-
- private File mDataDir;
-
- private class OwnersSub extends Owners {
- final File mLegacyFile;
- final File mDeviceOwnerFile;
- final File mProfileOwnerBase;
-
- public OwnersSub() {
- super(getContext());
- mLegacyFile = new File(mDataDir, LEGACY_FILE);
- mDeviceOwnerFile = new File(mDataDir, DEVICE_OWNER_FILE);
- mProfileOwnerBase = new File(mDataDir, PROFILE_OWNER_FILE_BASE);
- }
-
- @Override
- File getLegacyConfigFileWithTestOverride() {
- return mLegacyFile;
- }
-
- @Override
- File getDeviceOwnerFileWithTestOverride() {
- return mDeviceOwnerFile;
- }
-
- @Override
- File getProfileOwnerFileWithTestOverride(int userId) {
- return new File(mDeviceOwnerFile.getAbsoluteFile() + "-" + userId);
- }
- }
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
-
- mDataDir = new File(getContext().getCacheDir(), "OwnersTest");
- if (mDataDir.exists()) {
- assertTrue("failed to delete dir", FileUtils.deleteContents(mDataDir));
- }
- mDataDir.mkdirs();
- Log.i(TAG, "Created " + mDataDir);
- }
-
private String readAsset(String assetPath) throws IOException {
final StringBuilder sb = new StringBuilder();
try (BufferedReader br = new BufferedReader(
- new InputStreamReader((getContext().getResources().getAssets().open(assetPath))))) {
+ new InputStreamReader(
+ mRealTestContext.getResources().getAssets().open(assetPath)))) {
String line;
while ((line = br.readLine()) != null) {
sb.append(line);
@@ -126,7 +76,7 @@ public class OwnersTest extends DpmTestBase {
ui.id = userId;
userInfos.add(ui);
}
- when(getContext().getMockUserManager().getUsers()).thenReturn(userInfos);
+ when(getContext().userManager.getUsers()).thenReturn(userInfos);
}
public void testUpgrade01() throws Exception {
@@ -134,9 +84,10 @@ public class OwnersTest extends DpmTestBase {
// First, migrate.
{
- final OwnersSub owners = new OwnersSub();
+ final OwnersTestable owners = new OwnersTestable(getContext(), dataDir);
- createLegacyFile(owners.mLegacyFile, readAsset("OwnersTest/test01/input.xml"));
+ createLegacyFile(owners.getLegacyConfigFileWithTestOverride(),
+ readAsset("OwnersTest/test01/input.xml"));
owners.load();
@@ -160,7 +111,7 @@ public class OwnersTest extends DpmTestBase {
// Then re-read and check.
{
- final OwnersSub owners = new OwnersSub();
+ final OwnersTestable owners = new OwnersTestable(getContext(), dataDir);
owners.load();
assertFalse(owners.hasDeviceOwner());
@@ -176,9 +127,10 @@ public class OwnersTest extends DpmTestBase {
// First, migrate.
{
- final OwnersSub owners = new OwnersSub();
+ final OwnersTestable owners = new OwnersTestable(getContext(), dataDir);
- createLegacyFile(owners.mLegacyFile, readAsset("OwnersTest/test02/input.xml"));
+ createLegacyFile(owners.getLegacyConfigFileWithTestOverride(),
+ readAsset("OwnersTest/test02/input.xml"));
owners.load();
@@ -204,7 +156,7 @@ public class OwnersTest extends DpmTestBase {
// Then re-read and check.
{
- final OwnersSub owners = new OwnersSub();
+ final OwnersTestable owners = new OwnersTestable(getContext(), dataDir);
owners.load();
assertTrue(owners.hasDeviceOwner());
@@ -223,9 +175,10 @@ public class OwnersTest extends DpmTestBase {
// First, migrate.
{
- final OwnersSub owners = new OwnersSub();
+ final OwnersTestable owners = new OwnersTestable(getContext(), dataDir);
- createLegacyFile(owners.mLegacyFile, readAsset("OwnersTest/test03/input.xml"));
+ createLegacyFile(owners.getLegacyConfigFileWithTestOverride(),
+ readAsset("OwnersTest/test03/input.xml"));
owners.load();
@@ -259,7 +212,7 @@ public class OwnersTest extends DpmTestBase {
// Then re-read and check.
{
- final OwnersSub owners = new OwnersSub();
+ final OwnersTestable owners = new OwnersTestable(getContext(), dataDir);
owners.load();
assertFalse(owners.hasDeviceOwner());
@@ -286,9 +239,10 @@ public class OwnersTest extends DpmTestBase {
// First, migrate.
{
- final OwnersSub owners = new OwnersSub();
+ final OwnersTestable owners = new OwnersTestable(getContext(), dataDir);
- createLegacyFile(owners.mLegacyFile, readAsset("OwnersTest/test04/input.xml"));
+ createLegacyFile(owners.getLegacyConfigFileWithTestOverride(),
+ readAsset("OwnersTest/test04/input.xml"));
owners.load();
@@ -327,7 +281,7 @@ public class OwnersTest extends DpmTestBase {
// Then re-read and check.
{
- final OwnersSub owners = new OwnersSub();
+ final OwnersTestable owners = new OwnersTestable(getContext(), dataDir);
owners.load();
assertTrue(owners.hasDeviceOwner());
@@ -359,9 +313,10 @@ public class OwnersTest extends DpmTestBase {
// First, migrate.
{
- final OwnersSub owners = new OwnersSub();
+ final OwnersTestable owners = new OwnersTestable(getContext(), dataDir);
- createLegacyFile(owners.mLegacyFile, readAsset("OwnersTest/test05/input.xml"));
+ createLegacyFile(owners.getLegacyConfigFileWithTestOverride(),
+ readAsset("OwnersTest/test05/input.xml"));
owners.load();
@@ -386,7 +341,7 @@ public class OwnersTest extends DpmTestBase {
// Then re-read and check.
{
- final OwnersSub owners = new OwnersSub();
+ final OwnersTestable owners = new OwnersTestable(getContext(), dataDir);
owners.load();
assertFalse(owners.hasDeviceOwner());
@@ -405,9 +360,10 @@ public class OwnersTest extends DpmTestBase {
// First, migrate.
{
- final OwnersSub owners = new OwnersSub();
+ final OwnersTestable owners = new OwnersTestable(getContext(), dataDir);
- createLegacyFile(owners.mLegacyFile, readAsset("OwnersTest/test06/input.xml"));
+ createLegacyFile(owners.getLegacyConfigFileWithTestOverride(),
+ readAsset("OwnersTest/test06/input.xml"));
owners.load();
@@ -431,7 +387,7 @@ public class OwnersTest extends DpmTestBase {
// Then re-read and check.
{
- final OwnersSub owners = new OwnersSub();
+ final OwnersTestable owners = new OwnersTestable(getContext(), dataDir);
owners.load();
assertFalse(owners.hasDeviceOwner());
@@ -447,10 +403,11 @@ public class OwnersTest extends DpmTestBase {
public void testRemoveExistingFiles() throws Exception {
addUsersToUserManager(10, 11, 20, 21);
- final OwnersSub owners = new OwnersSub();
+ final OwnersTestable owners = new OwnersTestable(getContext(), dataDir);
// First, migrate to create new-style config files.
- createLegacyFile(owners.mLegacyFile, readAsset("OwnersTest/test04/input.xml"));
+ createLegacyFile(owners.getLegacyConfigFileWithTestOverride(),
+ readAsset("OwnersTest/test04/input.xml"));
owners.load();
diff --git a/services/usage/java/com/android/server/usage/UnixCalendar.java b/services/usage/java/com/android/server/usage/UnixCalendar.java
index ce06a91bd148..db7b42dca8fb 100644
--- a/services/usage/java/com/android/server/usage/UnixCalendar.java
+++ b/services/usage/java/com/android/server/usage/UnixCalendar.java
@@ -15,40 +15,22 @@
*/
package com.android.server.usage;
-import android.app.usage.UsageStatsManager;
-
/**
* A handy calendar object that knows nothing of Locale's or TimeZones. This simplifies
* interval book-keeping. It is *NOT* meant to be used as a user-facing calendar, as it has
* no concept of Locale or TimeZone.
*/
public class UnixCalendar {
- private static final long DAY_IN_MILLIS = 24 * 60 * 60 * 1000;
- private static final long WEEK_IN_MILLIS = 7 * DAY_IN_MILLIS;
- private static final long MONTH_IN_MILLIS = 30 * DAY_IN_MILLIS;
- private static final long YEAR_IN_MILLIS = 365 * DAY_IN_MILLIS;
+ public static final long DAY_IN_MILLIS = 24 * 60 * 60 * 1000;
+ public static final long WEEK_IN_MILLIS = 7 * DAY_IN_MILLIS;
+ public static final long MONTH_IN_MILLIS = 30 * DAY_IN_MILLIS;
+ public static final long YEAR_IN_MILLIS = 365 * DAY_IN_MILLIS;
private long mTime;
public UnixCalendar(long time) {
mTime = time;
}
- public void truncateToDay() {
- mTime -= mTime % DAY_IN_MILLIS;
- }
-
- public void truncateToWeek() {
- mTime -= mTime % WEEK_IN_MILLIS;
- }
-
- public void truncateToMonth() {
- mTime -= mTime % MONTH_IN_MILLIS;
- }
-
- public void truncateToYear() {
- mTime -= mTime % YEAR_IN_MILLIS;
- }
-
public void addDays(int val) {
mTime += val * DAY_IN_MILLIS;
}
@@ -72,28 +54,4 @@ public class UnixCalendar {
public long getTimeInMillis() {
return mTime;
}
-
- public static void truncateTo(UnixCalendar calendar, int intervalType) {
- switch (intervalType) {
- case UsageStatsManager.INTERVAL_YEARLY:
- calendar.truncateToYear();
- break;
-
- case UsageStatsManager.INTERVAL_MONTHLY:
- calendar.truncateToMonth();
- break;
-
- case UsageStatsManager.INTERVAL_WEEKLY:
- calendar.truncateToWeek();
- break;
-
- case UsageStatsManager.INTERVAL_DAILY:
- calendar.truncateToDay();
- break;
-
- default:
- throw new UnsupportedOperationException("Can't truncate date to interval " +
- intervalType);
- }
- }
}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
index f8ae03f1107c..0ca4bd8c6c04 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
@@ -350,23 +350,6 @@ class UsageStatsDatabase {
}
/**
- * Get the time at which the latest stats begin for this interval type.
- */
- public long getLatestUsageStatsBeginTime(int intervalType) {
- synchronized (mLock) {
- if (intervalType < 0 || intervalType >= mIntervalDirs.length) {
- throw new IllegalArgumentException("Bad interval type " + intervalType);
- }
-
- final int statsFileCount = mSortedStatFiles[intervalType].size();
- if (statsFileCount > 0) {
- return mSortedStatFiles[intervalType].keyAt(statsFileCount - 1);
- }
- return -1;
- }
- }
-
- /**
* Figures out what to extract from the given IntervalStats object.
*/
interface StatCombiner<T> {
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index b07b8153279d..5188e5fd1f7d 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -65,6 +65,11 @@ class UserUsageStatsService {
private final String mLogPrefix;
private final int mUserId;
+ private static final long[] INTERVAL_LENGTH = new long[] {
+ UnixCalendar.DAY_IN_MILLIS, UnixCalendar.WEEK_IN_MILLIS,
+ UnixCalendar.MONTH_IN_MILLIS, UnixCalendar.YEAR_IN_MILLIS
+ };
+
interface StatsUpdatedListener {
void onStatsUpdated();
}
@@ -104,18 +109,12 @@ class UserUsageStatsService {
// By calling loadActiveStats, we will
// generate new stats for each bucket.
- loadActiveStats(currentTimeMillis,/*force=*/ false, /*resetBeginIdleTime=*/ false);
+ loadActiveStats(currentTimeMillis, /*resetBeginIdleTime=*/ false);
} else {
// Set up the expiry date to be one day from the latest daily stat.
// This may actually be today and we will rollover on the first event
// that is reported.
- mDailyExpiryDate.setTimeInMillis(
- mCurrentStats[UsageStatsManager.INTERVAL_DAILY].beginTime);
- mDailyExpiryDate.addDays(1);
- mDailyExpiryDate.truncateToDay();
- Slog.i(TAG, mLogPrefix + "Rollover scheduled @ " +
- sDateFormat.format(mDailyExpiryDate.getTimeInMillis()) +
- "(" + mDailyExpiryDate.getTimeInMillis() + ")");
+ updateRolloverDeadline();
}
// Now close off any events that were open at the time this was saved.
@@ -170,7 +169,7 @@ class UserUsageStatsService {
void onTimeChanged(long oldTime, long newTime, boolean resetBeginIdleTime) {
persistActiveStats();
mDatabase.onTimeChanged(newTime - oldTime);
- loadActiveStats(newTime, /* force= */ true, resetBeginIdleTime);
+ loadActiveStats(newTime, resetBeginIdleTime);
}
void reportEvent(UsageEvents.Event event, long deviceUsageTime) {
@@ -237,7 +236,7 @@ class UserUsageStatsService {
new StatCombiner<UsageStats>() {
@Override
public void combine(IntervalStats stats, boolean mutable,
- List<UsageStats> accResult) {
+ List<UsageStats> accResult) {
if (!mutable) {
accResult.addAll(stats.packageStats.values());
return;
@@ -254,7 +253,7 @@ class UserUsageStatsService {
new StatCombiner<ConfigurationStats>() {
@Override
public void combine(IntervalStats stats, boolean mutable,
- List<ConfigurationStats> accResult) {
+ List<ConfigurationStats> accResult) {
if (!mutable) {
accResult.addAll(stats.configurations.values());
return;
@@ -448,7 +447,7 @@ class UserUsageStatsService {
persistActiveStats();
mDatabase.prune(currentTimeMillis);
- loadActiveStats(currentTimeMillis, /*force=*/ false, /*resetBeginIdleTime=*/ false);
+ loadActiveStats(currentTimeMillis, /*resetBeginIdleTime=*/ false);
final int continueCount = continuePreviousDay.size();
for (int i = 0; i < continueCount; i++) {
@@ -474,45 +473,28 @@ class UserUsageStatsService {
}
}
- /**
- * @param force To force all in-memory stats to be reloaded.
- */
- private void loadActiveStats(final long currentTimeMillis, boolean force,
- boolean resetBeginIdleTime) {
- final UnixCalendar tempCal = mDailyExpiryDate;
+ private void loadActiveStats(final long currentTimeMillis, boolean resetBeginIdleTime) {
for (int intervalType = 0; intervalType < mCurrentStats.length; intervalType++) {
- tempCal.setTimeInMillis(currentTimeMillis);
- UnixCalendar.truncateTo(tempCal, intervalType);
-
- if (!force && mCurrentStats[intervalType] != null &&
- mCurrentStats[intervalType].beginTime == tempCal.getTimeInMillis()) {
- // These are the same, no need to load them (in memory stats are always newer
- // than persisted stats).
- continue;
- }
-
- final long lastBeginTime = mDatabase.getLatestUsageStatsBeginTime(intervalType);
- if (lastBeginTime >= tempCal.getTimeInMillis()) {
+ final IntervalStats stats = mDatabase.getLatestUsageStats(intervalType);
+ if (stats != null && currentTimeMillis - 500 >= stats.endTime &&
+ currentTimeMillis < stats.beginTime + INTERVAL_LENGTH[intervalType]) {
if (DEBUG) {
Slog.d(TAG, mLogPrefix + "Loading existing stats @ " +
- sDateFormat.format(lastBeginTime) + "(" + lastBeginTime +
+ sDateFormat.format(stats.beginTime) + "(" + stats.beginTime +
") for interval " + intervalType);
}
- mCurrentStats[intervalType] = mDatabase.getLatestUsageStats(intervalType);
+ mCurrentStats[intervalType] = stats;
} else {
- mCurrentStats[intervalType] = null;
- }
-
- if (mCurrentStats[intervalType] == null) {
+ // No good fit remains.
if (DEBUG) {
Slog.d(TAG, "Creating new stats @ " +
- sDateFormat.format(tempCal.getTimeInMillis()) + "(" +
- tempCal.getTimeInMillis() + ") for interval " + intervalType);
-
+ sDateFormat.format(currentTimeMillis) + "(" +
+ currentTimeMillis + ") for interval " + intervalType);
}
+
mCurrentStats[intervalType] = new IntervalStats();
- mCurrentStats[intervalType].beginTime = tempCal.getTimeInMillis();
- mCurrentStats[intervalType].endTime = currentTimeMillis;
+ mCurrentStats[intervalType].beginTime = currentTimeMillis;
+ mCurrentStats[intervalType].endTime = currentTimeMillis + 1;
}
if (resetBeginIdleTime) {
@@ -522,12 +504,16 @@ class UserUsageStatsService {
}
}
mStatsChanged = false;
- mDailyExpiryDate.setTimeInMillis(currentTimeMillis);
+ updateRolloverDeadline();
+ }
+
+ private void updateRolloverDeadline() {
+ mDailyExpiryDate.setTimeInMillis(
+ mCurrentStats[UsageStatsManager.INTERVAL_DAILY].beginTime);
mDailyExpiryDate.addDays(1);
- mDailyExpiryDate.truncateToDay();
Slog.i(TAG, mLogPrefix + "Rollover scheduled @ " +
sDateFormat.format(mDailyExpiryDate.getTimeInMillis()) + "(" +
- tempCal.getTimeInMillis() + ")");
+ mDailyExpiryDate.getTimeInMillis() + ")");
}
//
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 0c3f9da73663..7f813ec59313 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -419,10 +419,9 @@ public class UsbDeviceManager {
private boolean setUsbConfig(String config) {
if (DEBUG) Slog.d(TAG, "setUsbConfig(" + config + ")");
// set the new configuration
- String oldConfig = SystemProperties.get(USB_CONFIG_PROPERTY);
- if (!config.equals(oldConfig)) {
- SystemProperties.set(USB_CONFIG_PROPERTY, config);
- }
+ // we always set it due to b/23631400, where adbd was getting killed
+ // and not restarted due to property timeouts on some devices
+ SystemProperties.set(USB_CONFIG_PROPERTY, config);
return waitForState(config);
}
diff --git a/services/usb/java/com/android/server/usb/UsbSettingsManager.java b/services/usb/java/com/android/server/usb/UsbSettingsManager.java
index 2cf42f09111d..154cbd30d836 100644
--- a/services/usb/java/com/android/server/usb/UsbSettingsManager.java
+++ b/services/usb/java/com/android/server/usb/UsbSettingsManager.java
@@ -517,7 +517,7 @@ class UsbSettingsManager {
com.android.internal.R.bool.config_disableUsbPermissionDialogs);
synchronized (mLock) {
- if (UserHandle.OWNER.equals(user)) {
+ if (UserHandle.SYSTEM.equals(user)) {
upgradeSingleUserLocked();
}
readSettingsLocked();
diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java
index 77fdb65f638f..094b3a94bd7b 100644
--- a/telecomm/java/android/telecom/Conference.java
+++ b/telecomm/java/android/telecom/Conference.java
@@ -65,6 +65,7 @@ public abstract class Conference extends Conferenceable {
private final List<Connection> mUnmodifiableConferenceableConnections =
Collections.unmodifiableList(mConferenceableConnections);
+ private String mTelecomCallId;
private PhoneAccountHandle mPhoneAccount;
private CallAudioState mCallAudioState;
private int mState = Connection.STATE_NEW;
@@ -94,6 +95,26 @@ public abstract class Conference extends Conferenceable {
}
/**
+ * Returns the telecom internal call ID associated with this conference.
+ *
+ * @return The telecom call ID.
+ * @hide
+ */
+ public final String getTelecomCallId() {
+ return mTelecomCallId;
+ }
+
+ /**
+ * Sets the telecom internal call ID associated with this conference.
+ *
+ * @param telecomCallId The telecom call ID.
+ * @hide
+ */
+ public final void setTelecomCallId(String telecomCallId) {
+ mTelecomCallId = telecomCallId;
+ }
+
+ /**
* Returns the {@link PhoneAccountHandle} the conference call is being placed through.
*
* @return A {@code PhoneAccountHandle} object representing the PhoneAccount of the conference.
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 430760a892b7..41157565bfdd 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -1074,6 +1074,8 @@ public abstract class Connection extends Conferenceable {
private final List<Conferenceable> mUnmodifiableConferenceables =
Collections.unmodifiableList(mConferenceables);
+ // The internal telecom call ID associated with this connection.
+ private String mTelecomCallId;
private int mState = STATE_NEW;
private CallAudioState mCallAudioState;
private Uri mAddress;
@@ -1098,6 +1100,17 @@ public abstract class Connection extends Conferenceable {
public Connection() {}
/**
+ * Returns the Telecom internal call ID associated with this connection. Should only be used
+ * for debugging and tracing purposes.
+ *
+ * @return The Telecom call ID.
+ * @hide
+ */
+ public final String getTelecomCallId() {
+ return mTelecomCallId;
+ }
+
+ /**
* @return The address (e.g., phone number) to which this Connection is currently communicating.
*/
public final Uri getAddress() {
@@ -1259,6 +1272,17 @@ public abstract class Connection extends Conferenceable {
}
/**
+ * Sets the telecom call ID associated with this Connection. The Telecom Call ID should be used
+ * ONLY for debugging purposes.
+ *
+ * @param callId The telecom call ID.
+ * @hide
+ */
+ public void setTelecomCallId(String callId) {
+ mTelecomCallId = callId;
+ }
+
+ /**
* Inform this Connection that the state of its audio output has been changed externally.
*
* @param state The new audio state.
diff --git a/telecomm/java/android/telecom/ConnectionRequest.java b/telecomm/java/android/telecom/ConnectionRequest.java
index 686321476bd1..aba38fe8a376 100644
--- a/telecomm/java/android/telecom/ConnectionRequest.java
+++ b/telecomm/java/android/telecom/ConnectionRequest.java
@@ -32,6 +32,7 @@ public final class ConnectionRequest implements Parcelable {
private final Uri mAddress;
private final Bundle mExtras;
private final int mVideoState;
+ private final String mTelecomCallId;
/**
* @param accountHandle The accountHandle which should be used to place the call.
@@ -42,7 +43,7 @@ public final class ConnectionRequest implements Parcelable {
PhoneAccountHandle accountHandle,
Uri handle,
Bundle extras) {
- this(accountHandle, handle, extras, VideoProfile.STATE_AUDIO_ONLY);
+ this(accountHandle, handle, extras, VideoProfile.STATE_AUDIO_ONLY, null);
}
/**
@@ -56,10 +57,28 @@ public final class ConnectionRequest implements Parcelable {
Uri handle,
Bundle extras,
int videoState) {
+ this(accountHandle, handle, extras, videoState, null);
+ }
+
+ /**
+ * @param accountHandle The accountHandle which should be used to place the call.
+ * @param handle The handle (e.g., phone number) to which the {@link Connection} is to connect.
+ * @param extras Application-specific extra data.
+ * @param videoState Determines the video state for the connection.
+ * @param telecomCallId The telecom call ID.
+ * @hide
+ */
+ public ConnectionRequest(
+ PhoneAccountHandle accountHandle,
+ Uri handle,
+ Bundle extras,
+ int videoState,
+ String telecomCallId) {
mAccountHandle = accountHandle;
mAddress = handle;
mExtras = extras;
mVideoState = videoState;
+ mTelecomCallId = telecomCallId;
}
private ConnectionRequest(Parcel in) {
@@ -67,6 +86,7 @@ public final class ConnectionRequest implements Parcelable {
mAddress = in.readParcelable(getClass().getClassLoader());
mExtras = in.readParcelable(getClass().getClassLoader());
mVideoState = in.readInt();
+ mTelecomCallId = in.readString();
}
/**
@@ -99,6 +119,16 @@ public final class ConnectionRequest implements Parcelable {
return mVideoState;
}
+ /**
+ * Returns the internal Telecom ID associated with the connection request.
+ *
+ * @return The Telecom ID.
+ * @hide
+ */
+ public String getTelecomCallId() {
+ return mTelecomCallId;
+ }
+
@Override
public String toString() {
return String.format("ConnectionRequest %s %s",
@@ -134,5 +164,6 @@ public final class ConnectionRequest implements Parcelable {
destination.writeParcelable(mAddress, 0);
destination.writeParcelable(mExtras, 0);
destination.writeInt(mVideoState);
+ destination.writeString(mTelecomCallId);
}
}
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 4e330bdbf67d..62234958517d 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -116,6 +116,8 @@ public abstract class ConnectionService extends Service {
private boolean mAreAccountsInitialized = false;
private Conference sNullConference;
+ private Object mIdSyncRoot = new Object();
+ private int mId = 0;
private final IBinder mBinder = new IConnectionService.Stub() {
@Override
@@ -629,7 +631,8 @@ public abstract class ConnectionService extends Service {
boolean isIncoming,
boolean isUnknown) {
Log.d(this, "createConnection, callManagerAccount: %s, callId: %s, request: %s, " +
- "isIncoming: %b, isUnknown: %b", callManagerAccount, callId, request, isIncoming,
+ "isIncoming: %b, isUnknown: %b", callManagerAccount, callId, request,
+ isIncoming,
isUnknown);
Connection connection = isUnknown ? onCreateUnknownConnection(callManagerAccount, request)
@@ -641,6 +644,7 @@ public abstract class ConnectionService extends Service {
new DisconnectCause(DisconnectCause.ERROR));
}
+ connection.setTelecomCallId(callId);
if (connection.getState() != Connection.STATE_DISCONNECTED) {
addConnection(callId, connection);
}
@@ -953,6 +957,7 @@ public abstract class ConnectionService extends Service {
connectionIds.add(mIdByConnection.get(connection));
}
}
+ conference.setTelecomCallId(id);
ParcelableConference parcelableConference = new ParcelableConference(
conference.getPhoneAccountHandle(),
conference.getState(),
@@ -989,7 +994,7 @@ public abstract class ConnectionService extends Service {
public final void addExistingConnection(PhoneAccountHandle phoneAccountHandle,
Connection connection) {
- String id = addExistingConnectionInternal(connection);
+ String id = addExistingConnectionInternal(phoneAccountHandle, connection);
if (id != null) {
List<String> emptyList = new ArrayList<>(0);
@@ -1151,18 +1156,29 @@ public abstract class ConnectionService extends Service {
}
/**
- * Adds an existing connection to the list of connections, identified by a new UUID.
+ * Adds an existing connection to the list of connections, identified by a new call ID unique
+ * to this connection service.
*
* @param connection The connection.
- * @return The UUID of the connection (e.g. the call-id).
+ * @return The ID of the connection (e.g. the call-id).
*/
- private String addExistingConnectionInternal(Connection connection) {
- String id = UUID.randomUUID().toString();
+ private String addExistingConnectionInternal(PhoneAccountHandle handle, Connection connection) {
+ String id;
+ if (handle == null) {
+ // If no phone account handle was provided, we cannot be sure the call ID is unique,
+ // so just use a random UUID.
+ id = UUID.randomUUID().toString();
+ } else {
+ // Phone account handle was provided, so use the ConnectionService class name as a
+ // prefix for a unique incremental call ID.
+ id = handle.getComponentName().getClassName() + "@" + getNextCallId();
+ }
addConnection(id, connection);
return id;
}
private void addConnection(String callId, Connection connection) {
+ connection.setTelecomCallId(callId);
mConnectionById.put(callId, connection);
mIdByConnection.put(connection, callId);
connection.addConnectionListener(mConnectionListener);
@@ -1183,6 +1199,9 @@ public abstract class ConnectionService extends Service {
if (mIdByConference.containsKey(conference)) {
Log.w(this, "Re-adding an existing conference: %s.", conference);
} else if (conference != null) {
+ // Conferences do not (yet) have a PhoneAccountHandle associated with them, so we
+ // cannot determine a ConnectionService class name to associate with the ID, so use
+ // a unique UUID (for now).
String id = UUID.randomUUID().toString();
mConferenceById.put(id, conference);
mIdByConference.put(conference, id);
@@ -1284,4 +1303,15 @@ public abstract class ConnectionService extends Service {
conference.onDisconnect();
}
}
+
+ /**
+ * Retrieves the next call ID as maintainted by the connection service.
+ *
+ * @return The call ID.
+ */
+ private int getNextCallId() {
+ synchronized(mIdSyncRoot) {
+ return ++mId;
+ }
+ }
}
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/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 0e858de32229..e57964a96182 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -78,6 +78,15 @@ public class CarrierConfigManager {
public static final String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
/**
+ * Flag to require or skip entitlement checks.
+ * If true, entitlement checks will be executed if device has been configured for it,
+ * If false, entitlement checks will be skipped.
+ * @hide
+ */
+ public static final String
+ KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL = "require_entitlement_checks_bool";
+
+ /**
* If true, enable vibration (haptic feedback) for key presses in the EmergencyDialer activity.
* The pattern is set on a per-platform basis using config_virtualKeyVibePattern. To be
* consistent with the regular Dialer, this value should agree with the corresponding values
@@ -317,6 +326,14 @@ public class CarrierConfigManager {
public static final String KEY_CARRIER_FORCE_DISABLE_ETWS_CMAS_TEST_BOOL =
"carrier_force_disable_etws_cmas_test_bool";
+ /**
+ * The default flag specifying whether "Turn on Notifications" option will be always shown in
+ * Settings->More->Emergency broadcasts menu regardless developer options is turned on or not.
+ * @hide
+ */
+ public static final String KEY_ALWAYS_SHOW_EMERGENCY_ALERT_ONOFF_BOOL =
+ "always_show_emergency_alert_onoff_bool";
+
/* The following 3 fields are related to carrier visual voicemail. */
/**
@@ -511,6 +528,7 @@ public class CarrierConfigManager {
sDefaults.putBoolean(KEY_VOICEMAIL_NOTIFICATION_PERSISTENT_BOOL, false);
sDefaults.putBoolean(KEY_VOICE_PRIVACY_DISABLE_UI_BOOL, false);
sDefaults.putBoolean(KEY_WORLD_PHONE_BOOL, false);
+ sDefaults.putBoolean(KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL, true);
sDefaults.putInt(KEY_VOLTE_REPLACEMENT_RAT_INT, 0);
sDefaults.putString(KEY_DEFAULT_SIM_CALL_MANAGER_STRING, "");
sDefaults.putString(KEY_VVM_DESTINATION_NUMBER_STRING, "");
@@ -522,6 +540,7 @@ public class CarrierConfigManager {
sDefaults.putString(KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_STRING, "");
sDefaults.putString(KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_VAL_STRING, "");
sDefaults.putBoolean(KEY_CSP_ENABLED_BOOL, false);
+ sDefaults.putBoolean(KEY_ALWAYS_SHOW_EMERGENCY_ALERT_ONOFF_BOOL, false);
sDefaults.putStringArray(KEY_GSM_ROAMING_NETWORKS_STRING_ARRAY, null);
sDefaults.putStringArray(KEY_GSM_NONROAMING_NETWORKS_STRING_ARRAY, null);
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index f6e4bed86b16..d22727d14829 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -3611,11 +3611,12 @@ public class TelephonyManager {
*
* @hide
*/
- public boolean setNetworkSelectionModeManual(int subId, OperatorInfo operator) {
+ public boolean setNetworkSelectionModeManual(int subId, OperatorInfo operator,
+ boolean persistSelection) {
try {
ITelephony telephony = getITelephony();
if (telephony != null)
- return telephony.setNetworkSelectionModeManual(subId, operator);
+ return telephony.setNetworkSelectionModeManual(subId, operator, persistSelection);
} catch (RemoteException ex) {
Rlog.e(TAG, "setNetworkSelectionModeManual RemoteException", ex);
} catch (NullPointerException ex) {
diff --git a/telephony/java/com/android/internal/telephony/CallerInfo.java b/telephony/java/com/android/internal/telephony/CallerInfo.java
index be7e7029115b..59a8a67f85a2 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfo.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfo.java
@@ -249,9 +249,17 @@ public class CallerInfo {
// look for the custom ringtone, create from the string stored
// in the database.
+ // An empty string ("") in the database indicates a silent ringtone,
+ // and we set contactRingtoneUri = Uri.EMPTY, so that no ringtone will be played.
+ // {null} in the database indicates the default ringtone,
+ // and we set contactRingtoneUri = null, so that default ringtone will be played.
columnIndex = cursor.getColumnIndex(PhoneLookup.CUSTOM_RINGTONE);
if ((columnIndex != -1) && (cursor.getString(columnIndex) != null)) {
- info.contactRingtoneUri = Uri.parse(cursor.getString(columnIndex));
+ if (TextUtils.isEmpty(cursor.getString(columnIndex))) {
+ info.contactRingtoneUri = Uri.EMPTY;
+ } else {
+ info.contactRingtoneUri = Uri.parse(cursor.getString(columnIndex));
+ }
} else {
info.contactRingtoneUri = null;
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 661f12db3f9c..dcece26d6c27 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -707,9 +707,13 @@ interface ITelephony {
*
* @param subId the id of the subscription.
* @param operatorInfo the operator to attach to.
+ * @param persistSelection should the selection persist till reboot or its
+ * turned off? Will also result in notification being not shown to
+ * the user if the signal is lost.
* @return true if the request suceeded.
*/
- boolean setNetworkSelectionModeManual(int subId, in OperatorInfo operator);
+ boolean setNetworkSelectionModeManual(int subId, in OperatorInfo operator,
+ boolean persistSelection);
/**
* Set the preferred network type.
diff --git a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
index 5fbfe8ace7e1..ceb3993e1705 100644
--- a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
+++ b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
@@ -57,6 +57,7 @@ import android.content.pm.UserInfo;
import android.content.res.Configuration;
import android.util.Log;
+
public class ActivityTestMain extends Activity {
static final String TAG = "ActivityTest";
@@ -315,7 +316,7 @@ public class ActivityTestMain extends Activity {
Log.i(TAG, "Service disconnected " + name);
}
};
- if (bindServiceAsUser(intent, conn, Context.BIND_AUTO_CREATE, UserHandle.OWNER)) {
+ if (bindServiceAsUser(intent, conn, Context.BIND_AUTO_CREATE, UserHandle.SYSTEM)) {
mConnections.add(conn);
} else {
Toast.makeText(ActivityTestMain.this, "Failed to bind",
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/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 10cf5c1b2f8b..b028ce61f821 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -944,5 +944,14 @@
</intent-filter>
</activity>
+ <activity
+ android:name="MultiProducerActivity"
+ android:label="Threads/Multiple Producers">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.android.test.hwui.TEST" />
+ </intent-filter>
+ </activity>
+
</application>
</manifest>
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/MultiProducerActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/MultiProducerActivity.java
new file mode 100644
index 000000000000..b458d9b14096
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/MultiProducerActivity.java
@@ -0,0 +1,347 @@
+/*
+ * 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.test.hwui;
+
+import android.app.Activity;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.view.DisplayListCanvas;
+import android.view.HardwareRenderer;
+import android.view.RenderNode;
+import android.view.ThreadedRenderer;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.AbsoluteLayout;
+import android.widget.AbsoluteLayout.LayoutParams;
+
+public class MultiProducerActivity extends Activity implements OnClickListener {
+ private static final int DURATION = 800;
+ private View mBackgroundTarget = null;
+ private View mFrameTarget = null;
+ private View mContent = null;
+ // The width & height of our "output drawing".
+ private final int WIDTH = 900;
+ private final int HEIGHT = 600;
+ // A border width around the drawing.
+ private static final int BORDER_WIDTH = 20;
+ // The Gap between the content and the frame which should get filled on the right and bottom
+ // side by the backdrop.
+ final int CONTENT_GAP = 100;
+
+ // For debug purposes - disable drawing of frame / background.
+ private final boolean USE_FRAME = true;
+ private final boolean USE_BACK = true;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ // To make things simple - we do a quick and dirty absolute layout.
+ final AbsoluteLayout layout = new AbsoluteLayout(this);
+
+ // Create the outer frame
+ if (USE_FRAME) {
+ mFrameTarget = new View(this);
+ LayoutParams frameLP = new LayoutParams(WIDTH, HEIGHT, 0, 0);
+ layout.addView(mFrameTarget, frameLP);
+ }
+
+ // Create the background which fills the gap between content and frame.
+ if (USE_BACK) {
+ mBackgroundTarget = new View(this);
+ LayoutParams backgroundLP = new LayoutParams(
+ WIDTH - 2 * BORDER_WIDTH, HEIGHT - 2 * BORDER_WIDTH,
+ BORDER_WIDTH, BORDER_WIDTH);
+ layout.addView(mBackgroundTarget, backgroundLP);
+ }
+
+ // Create the content
+ // Note: We reduce the size by CONTENT_GAP pixels on right and bottom, so that they get
+ // drawn by the backdrop.
+ mContent = new View(this);
+ mContent.setBackground(new ColorPulse(0xFFF44336, 0xFF9C27B0, null));
+ mContent.setOnClickListener(this);
+ LayoutParams contentLP = new LayoutParams(WIDTH - 2 * BORDER_WIDTH - CONTENT_GAP,
+ HEIGHT - 2 * BORDER_WIDTH - CONTENT_GAP, BORDER_WIDTH, BORDER_WIDTH);
+ layout.addView(mContent, contentLP);
+
+ setContentView(layout);
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ View view = mBackgroundTarget != null ? mBackgroundTarget : mFrameTarget;
+ if (view != null) {
+ view.post(mSetup);
+ }
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ View view = mBackgroundTarget != null ? mBackgroundTarget : mFrameTarget;
+ if (view != null) {
+ view.removeCallbacks(mSetup);
+ }
+ if (mBgRenderer != null) {
+ mBgRenderer.destroy();
+ mBgRenderer = null;
+ }
+ }
+
+ @Override
+ public void onClick(View view) {
+ sBlockThread.run();
+ }
+
+ private Runnable mSetup = new Runnable() {
+ @Override
+ public void run() {
+ View view = mBackgroundTarget != null ? mBackgroundTarget : mFrameTarget;
+ if (view == null) {
+ view.postDelayed(mSetup, 50);
+ }
+ HardwareRenderer renderer = view.getHardwareRenderer();
+ if (renderer == null || view.getWidth() == 0) {
+ view.postDelayed(mSetup, 50);
+ }
+ ThreadedRenderer threaded = (ThreadedRenderer) renderer;
+
+ mBgRenderer = new FakeFrame(threaded,mFrameTarget, mBackgroundTarget);
+ mBgRenderer.start();
+ }
+ };
+
+ private FakeFrame mBgRenderer;
+ private class FakeFrame extends Thread {
+ ThreadedRenderer mRenderer;
+ volatile boolean mRunning = true;
+ View mTargetFrame;
+ View mTargetBack;
+ Drawable mFrameContent;
+ Drawable mBackContent;
+ // The Z value where to place this.
+ int mZFrame;
+ int mZBack;
+ String mRenderNodeName;
+
+ FakeFrame(ThreadedRenderer renderer, View targetFrame, View targetBack) {
+ mRenderer = renderer;
+ mTargetFrame = targetFrame;
+
+ mTargetBack = targetBack;
+ mFrameContent = new ColorPulse(0xFF101010, 0xFF707070, new Rect(0, 0, WIDTH, HEIGHT));
+ mBackContent = new ColorPulse(0xFF909090, 0xFFe0e0e0, null);
+ }
+
+ @Override
+ public void run() {
+ Rect currentFrameBounds = new Rect();
+ Rect currentBackBounds = new Rect();
+ Rect newBounds = new Rect();
+ int[] surfaceOrigin = new int[2];
+ RenderNode nodeFrame = null;
+ RenderNode nodeBack = null;
+
+ // Since we are overriding the window painting logic we need to at least fill the
+ // surface with some window content (otherwise the world will go black).
+ try {
+ Thread.sleep(200);
+ } catch (InterruptedException e) {
+ }
+
+ if (mTargetBack != null) {
+ nodeBack = RenderNode.create("FakeBackdrop", null);
+ nodeBack.setClipToBounds(true);
+ mRenderer.addRenderNode(nodeBack, true);
+ }
+
+ if (mTargetFrame != null) {
+ nodeFrame = RenderNode.create("FakeFrame", null);
+ nodeFrame.setClipToBounds(true);
+ mRenderer.addRenderNode(nodeFrame, false);
+ }
+
+ while (mRunning) {
+ // Get the surface position to draw to within our surface.
+ surfaceOrigin[0] = 0;
+ surfaceOrigin[1] = 0;
+ // 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],
+ surfaceOrigin[0] + mContent.getWidth(),
+ surfaceOrigin[1] + mContent.getHeight());
+ // Determine new position for frame.
+ if (nodeFrame != null) {
+ surfaceOrigin[0] = 0;
+ surfaceOrigin[1] = 0;
+ mTargetFrame.getLocationInSurface(surfaceOrigin);
+ newBounds.set(surfaceOrigin[0], surfaceOrigin[1],
+ surfaceOrigin[0] + mTargetFrame.getWidth(),
+ surfaceOrigin[1] + mTargetFrame.getHeight());
+ if (!currentFrameBounds.equals(newBounds)) {
+ currentFrameBounds.set(newBounds);
+ nodeFrame.setLeftTopRightBottom(currentFrameBounds.left,
+ currentFrameBounds.top,
+ currentFrameBounds.right, currentFrameBounds.bottom);
+ }
+
+ // Draw frame
+ DisplayListCanvas canvas = nodeFrame.start(currentFrameBounds.width(),
+ currentFrameBounds.height());
+ mFrameContent.draw(canvas);
+ nodeFrame.end(canvas);
+ }
+
+ // Determine new position for backdrop
+ if (nodeBack != null) {
+ surfaceOrigin[0] = 0;
+ surfaceOrigin[1] = 0;
+ mTargetBack.getLocationInSurface(surfaceOrigin);
+ newBounds.set(surfaceOrigin[0], surfaceOrigin[1],
+ surfaceOrigin[0] + mTargetBack.getWidth(),
+ surfaceOrigin[1] + mTargetBack.getHeight());
+ if (!currentBackBounds.equals(newBounds)) {
+ currentBackBounds.set(newBounds);
+ nodeBack.setLeftTopRightBottom(currentBackBounds.left,
+ currentBackBounds.top,
+ currentBackBounds.right, currentBackBounds.bottom);
+ }
+
+ // Draw Backdrop
+ DisplayListCanvas canvas = nodeBack.start(currentBackBounds.width(),
+ currentBackBounds.height());
+ mBackContent.draw(canvas);
+ nodeBack.end(canvas);
+ }
+
+ // we need to only render one guy - the rest will happen automatically (I think).
+ if (nodeFrame != null) {
+ mRenderer.drawRenderNode(nodeFrame);
+ }
+ if (nodeBack != null) {
+ mRenderer.drawRenderNode(nodeBack);
+ }
+ try {
+ Thread.sleep(5);
+ } catch (InterruptedException e) {}
+ }
+ if (nodeFrame != null) {
+ mRenderer.removeRenderNode(nodeFrame);
+ }
+ if (nodeBack != null) {
+ mRenderer.removeRenderNode(nodeBack);
+ }
+ }
+
+ public void destroy() {
+ mRunning = false;
+ try {
+ join();
+ } catch (InterruptedException e) {}
+ }
+ }
+
+ private final static Runnable sBlockThread = new Runnable() {
+ @Override
+ public void run() {
+ try {
+ Thread.sleep(DURATION);
+ } catch (InterruptedException e) {
+ }
+ }
+ };
+
+ static class ColorPulse extends Drawable {
+
+ private int mColorStart;
+ private int mColorEnd;
+ private int mStep;
+ private Rect mRect;
+ private Paint mPaint = new Paint();
+
+ public ColorPulse(int color1, int color2, Rect rect) {
+ mColorStart = color1;
+ mColorEnd = color2;
+ if (rect != null) {
+ mRect = new Rect(rect.left + BORDER_WIDTH / 2, rect.top + BORDER_WIDTH / 2,
+ rect.right - BORDER_WIDTH / 2, rect.bottom - BORDER_WIDTH / 2);
+ }
+ }
+
+ static int evaluate(float fraction, int startInt, int endInt) {
+ int startA = (startInt >> 24) & 0xff;
+ int startR = (startInt >> 16) & 0xff;
+ int startG = (startInt >> 8) & 0xff;
+ int startB = startInt & 0xff;
+
+ int endA = (endInt >> 24) & 0xff;
+ int endR = (endInt >> 16) & 0xff;
+ int endG = (endInt >> 8) & 0xff;
+ int endB = endInt & 0xff;
+
+ return (int)((startA + (int)(fraction * (endA - startA))) << 24) |
+ (int)((startR + (int)(fraction * (endR - startR))) << 16) |
+ (int)((startG + (int)(fraction * (endG - startG))) << 8) |
+ (int)((startB + (int)(fraction * (endB - startB))));
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ float frac = mStep / 50.0f;
+ int color = evaluate(frac, mColorStart, mColorEnd);
+ if (mRect != null && !mRect.isEmpty()) {
+ mPaint.setStyle(Paint.Style.STROKE);
+ mPaint.setStrokeWidth(BORDER_WIDTH);
+ mPaint.setColor(color);
+ canvas.drawRect(mRect, mPaint);
+ } else {
+ canvas.drawColor(color);
+ }
+
+ mStep++;
+ if (mStep >= 50) {
+ mStep = 0;
+ int tmp = mColorStart;
+ mColorStart = mColorEnd;
+ mColorEnd = tmp;
+ }
+ invalidateSelf();
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter colorFilter) {
+ }
+
+ @Override
+ public int getOpacity() {
+ return mRect == null || mRect.isEmpty() ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT;
+ }
+
+ }
+}
+
diff --git a/tests/UiBench/Android.mk b/tests/UiBench/Android.mk
index 24df85b1841f..0e678cde9c70 100644
--- a/tests/UiBench/Android.mk
+++ b/tests/UiBench/Android.mk
@@ -11,17 +11,20 @@ LOCAL_SRC_FILES := $(call all-java-files-under,src)
LOCAL_RESOURCE_DIR := \
$(LOCAL_PATH)/res \
frameworks/support/v7/appcompat/res \
- frameworks/support/v7/cardview/res
+ frameworks/support/v7/cardview/res \
+ frameworks/support/v7/recyclerview/res
LOCAL_AAPT_FLAGS := \
--auto-add-overlay \
--extra-packages android.support.v7.appcompat \
- --extra-packages android.support.v7.cardview
+ --extra-packages android.support.v7.cardview \
+ --extra-packages android.support.v7.recyclerview
LOCAL_STATIC_JAVA_LIBRARIES := \
android-support-v4 \
android-support-v7-appcompat \
- android-support-v7-cardview
+ android-support-v7-cardview \
+ android-support-v7-recyclerview
LOCAL_PACKAGE_NAME := UiBench
diff --git a/tests/UiBench/AndroidManifest.xml b/tests/UiBench/AndroidManifest.xml
index 9b3d18668aa9..7b4f01cad849 100644
--- a/tests/UiBench/AndroidManifest.xml
+++ b/tests/UiBench/AndroidManifest.xml
@@ -83,6 +83,30 @@
<category android:name="com.android.test.uibench.TEST" />
</intent-filter>
</activity>
+ <activity
+ android:name=".TrivialRecyclerViewActivity"
+ android:label="General/Trivial Recycler ListView" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.android.test.uibench.TEST" />
+ </intent-filter>
+ </activity>
+ <activity
+ android:name=".ActivityTransition"
+ android:label="Transitions/Activity Transition" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.android.test.uibench.TEST" />
+ </intent-filter>
+ </activity>
+ <activity
+ android:name=".ActivityTransitionDetails"
+ android:label="Transitions/Activity Transition " >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <!-- Part of ActivityTransition test above, so not in TEST category -->
+ </intent-filter>
+ </activity>
<!-- Rendering -->
<activity
diff --git a/tests/UiBench/build.gradle b/tests/UiBench/build.gradle
index deecbb6392d1..0756a8aac878 100644
--- a/tests/UiBench/build.gradle
+++ b/tests/UiBench/build.gradle
@@ -32,7 +32,8 @@ android {
dependencies {
// Dependencies enumerated specifically for platform-independent / reproducible builds.
- compile 'com.android.support:support-v4:23.0.0'
- compile 'com.android.support:appcompat-v7:23.0.0'
- compile 'com.android.support:cardview-v7:23.0.0'
+ compile 'com.android.support:support-v4:23.0.1'
+ compile 'com.android.support:appcompat-v7:23.0.1'
+ compile 'com.android.support:cardview-v7:23.0.1'
+ compile 'com.android.support:recyclerview-v7:23.0.1'
}
diff --git a/tests/UiBench/res/drawable-nodpi/ball.jpg b/tests/UiBench/res/drawable-nodpi/ball.jpg
new file mode 100644
index 000000000000..2960b7309f6e
--- /dev/null
+++ b/tests/UiBench/res/drawable-nodpi/ball.jpg
Binary files differ
diff --git a/tests/UiBench/res/drawable-nodpi/block.jpg b/tests/UiBench/res/drawable-nodpi/block.jpg
new file mode 100644
index 000000000000..04c22a0cf5b4
--- /dev/null
+++ b/tests/UiBench/res/drawable-nodpi/block.jpg
Binary files differ
diff --git a/tests/UiBench/res/drawable-nodpi/ducky.jpg b/tests/UiBench/res/drawable-nodpi/ducky.jpg
new file mode 100644
index 000000000000..830bbe347e47
--- /dev/null
+++ b/tests/UiBench/res/drawable-nodpi/ducky.jpg
Binary files differ
diff --git a/tests/UiBench/res/drawable-nodpi/frantic.jpg b/tests/UiBench/res/drawable-nodpi/frantic.jpg
new file mode 100644
index 000000000000..4c623336e15b
--- /dev/null
+++ b/tests/UiBench/res/drawable-nodpi/frantic.jpg
Binary files differ
diff --git a/tests/UiBench/res/drawable-nodpi/jellies.jpg b/tests/UiBench/res/drawable-nodpi/jellies.jpg
new file mode 100644
index 000000000000..ee2b5c68c43b
--- /dev/null
+++ b/tests/UiBench/res/drawable-nodpi/jellies.jpg
Binary files differ
diff --git a/tests/UiBench/res/drawable-nodpi/mug.jpg b/tests/UiBench/res/drawable-nodpi/mug.jpg
new file mode 100644
index 000000000000..e149e198a9cd
--- /dev/null
+++ b/tests/UiBench/res/drawable-nodpi/mug.jpg
Binary files differ
diff --git a/tests/UiBench/res/drawable-nodpi/pencil.jpg b/tests/UiBench/res/drawable-nodpi/pencil.jpg
new file mode 100644
index 000000000000..e348311bf4d0
--- /dev/null
+++ b/tests/UiBench/res/drawable-nodpi/pencil.jpg
Binary files differ
diff --git a/tests/UiBench/res/drawable-nodpi/scissors.jpg b/tests/UiBench/res/drawable-nodpi/scissors.jpg
new file mode 100644
index 000000000000..caf0ce8e2f4b
--- /dev/null
+++ b/tests/UiBench/res/drawable-nodpi/scissors.jpg
Binary files differ
diff --git a/tests/UiBench/res/drawable-nodpi/woot.jpg b/tests/UiBench/res/drawable-nodpi/woot.jpg
new file mode 100644
index 000000000000..ccaef674b1a5
--- /dev/null
+++ b/tests/UiBench/res/drawable-nodpi/woot.jpg
Binary files differ
diff --git a/tests/UiBench/res/layout/activity_transition.xml b/tests/UiBench/res/layout/activity_transition.xml
new file mode 100644
index 000000000000..d4c661027a35
--- /dev/null
+++ b/tests/UiBench/res/layout/activity_transition.xml
@@ -0,0 +1,103 @@
+<?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
+ -->
+<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:clipChildren="true"
+ android:columnCount="2"
+ android:rowCount="4">
+ <ImageView
+ android:id="@+id/ducky"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:scaleType="centerCrop"
+ android:layout_column="0"
+ android:layout_row="0"
+ android:src="@drawable/ducky"
+ android:onClick="clicked"
+ android:transitionName="ducky"/>
+ <ImageView
+ android:id="@+id/woot"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:scaleType="centerCrop"
+ android:src="@drawable/woot"
+ android:layout_column="1"
+ android:layout_row="0"
+ android:onClick="clicked"
+ android:transitionName="woot"/>
+ <ImageView
+ android:id="@+id/ball"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:scaleType="centerCrop"
+ android:src="@drawable/ball"
+ android:layout_column="0"
+ android:layout_row="1"
+ android:onClick="clicked"
+ android:transitionName="ball"/>
+ <ImageView
+ android:id="@+id/block"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:scaleType="centerCrop"
+ android:src="@drawable/block"
+ android:layout_column="1"
+ android:layout_row="1"
+ android:onClick="clicked"
+ android:transitionName="block"/>
+ <ImageView
+ android:id="@+id/jellies"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:scaleType="centerCrop"
+ android:src="@drawable/jellies"
+ android:layout_column="0"
+ android:layout_row="2"
+ android:onClick="clicked"
+ android:transitionName="jellies"/>
+ <ImageView
+ android:id="@+id/mug"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:scaleType="centerCrop"
+ android:src="@drawable/mug"
+ android:layout_column="1"
+ android:layout_row="2"
+ android:onClick="clicked"
+ android:transitionName="mug"/>
+ <ImageView
+ android:id="@+id/pencil"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:scaleType="centerCrop"
+ android:src="@drawable/pencil"
+ android:layout_column="0"
+ android:layout_row="3"
+ android:onClick="clicked"
+ android:transitionName="pencil"/>
+ <ImageView
+ android:id="@+id/scissors"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:scaleType="centerCrop"
+ android:src="@drawable/scissors"
+ android:layout_column="1"
+ android:layout_row="3"
+ android:onClick="clicked"
+ android:transitionName="scissors"/>
+</GridLayout> \ No newline at end of file
diff --git a/tests/UiBench/res/layout/activity_transition_details.xml b/tests/UiBench/res/layout/activity_transition_details.xml
new file mode 100644
index 000000000000..1022d2fc2a40
--- /dev/null
+++ b/tests/UiBench/res/layout/activity_transition_details.xml
@@ -0,0 +1,39 @@
+<?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
+ -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+ <ImageView
+ android:id="@+id/titleImage"
+ android:layout_height="0px"
+ android:layout_weight="1"
+ android:layout_width="match_parent"
+ android:scaleType="centerCrop"
+ android:transitionName="hero"
+ android:onClick="clicked"/>
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="2dp"
+ android:background="#808080"/>
+ <TextView
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:text="Sample Picture"
+ android:textSize="30sp"
+ android:textColor="#FFF"/>
+</LinearLayout> \ No newline at end of file
diff --git a/tests/UiBench/res/layout/recycler_view.xml b/tests/UiBench/res/layout/recycler_view.xml
new file mode 100644
index 000000000000..54c5b5845ae2
--- /dev/null
+++ b/tests/UiBench/res/layout/recycler_view.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.support.v7.widget.RecyclerView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/recyclerView"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
diff --git a/tests/UiBench/src/com/android/test/uibench/ActivityTransition.java b/tests/UiBench/src/com/android/test/uibench/ActivityTransition.java
new file mode 100644
index 000000000000..1106a13bfc2a
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/ActivityTransition.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 com.android.test.uibench;
+
+import android.app.ActivityOptions;
+import android.app.SharedElementCallback;
+import android.content.Intent;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.view.View;
+import android.widget.ImageView;
+
+import java.util.List;
+import java.util.Map;
+
+public class ActivityTransition extends AppCompatActivity {
+ private static final String KEY_ID = "ViewTransitionValues:id";
+
+ private ImageView mHero;
+
+ public static final int[] DRAWABLES = {
+ R.drawable.ball,
+ R.drawable.block,
+ R.drawable.ducky,
+ R.drawable.jellies,
+ R.drawable.mug,
+ R.drawable.pencil,
+ R.drawable.scissors,
+ R.drawable.woot,
+ };
+
+ public static final int[] IDS = {
+ R.id.ball,
+ R.id.block,
+ R.id.ducky,
+ R.id.jellies,
+ R.id.mug,
+ R.id.pencil,
+ R.id.scissors,
+ R.id.woot,
+ };
+
+ public static final String[] NAMES = {
+ "ball",
+ "block",
+ "ducky",
+ "jellies",
+ "mug",
+ "pencil",
+ "scissors",
+ "woot",
+ };
+
+ public static int getIdForKey(String id) {
+ return IDS[getIndexForKey(id)];
+ }
+
+ public static int getDrawableIdForKey(String id) {
+ return DRAWABLES[getIndexForKey(id)];
+ }
+
+ public static int getIndexForKey(String id) {
+ for (int i = 0; i < NAMES.length; i++) {
+ String name = NAMES[i];
+ if (name.equals(id)) {
+ return i;
+ }
+ }
+ return 2;
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ getWindow().setBackgroundDrawable(new ColorDrawable(Color.BLACK));
+ setContentView(R.layout.activity_transition);
+ setupHero();
+ }
+
+ private void setupHero() {
+ String name = getIntent().getStringExtra(KEY_ID);
+ mHero = null;
+ if (name != null) {
+ mHero = (ImageView) findViewById(getIdForKey(name));
+ setEnterSharedElementCallback(new SharedElementCallback() {
+ @Override
+ public void onMapSharedElements(List<String> names,
+ Map<String, View> sharedElements) {
+ sharedElements.put("hero", mHero);
+ }
+ });
+ }
+ }
+
+ public void clicked(View v) {
+ mHero = (ImageView) v;
+ Intent intent = new Intent(this, ActivityTransitionDetails.class);
+ intent.putExtra(KEY_ID, v.getTransitionName());
+ ActivityOptions activityOptions
+ = ActivityOptions.makeSceneTransitionAnimation(this, mHero, "hero");
+ startActivity(intent, activityOptions.toBundle());
+ }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/ActivityTransitionDetails.java b/tests/UiBench/src/com/android/test/uibench/ActivityTransitionDetails.java
new file mode 100644
index 000000000000..a654c6107134
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/ActivityTransitionDetails.java
@@ -0,0 +1,63 @@
+/*
+ * 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.test.uibench;
+
+import android.app.ActivityOptions;
+import android.content.Intent;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.view.View;
+import android.widget.ImageView;
+
+import com.android.test.uibench.ActivityTransition;
+import com.android.test.uibench.R;
+
+
+public class ActivityTransitionDetails extends AppCompatActivity {
+ private static final String KEY_ID = "ViewTransitionValues:id";
+ private int mImageResourceId = R.drawable.ducky;
+ private String mName = "ducky";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ getWindow().setBackgroundDrawable(new ColorDrawable(Color.DKGRAY));
+ setContentView(R.layout.activity_transition_details);
+ ImageView titleImage = (ImageView) findViewById(R.id.titleImage);
+ titleImage.setImageDrawable(getHeroDrawable());
+ }
+
+ private Drawable getHeroDrawable() {
+ String name = getIntent().getStringExtra(KEY_ID);
+ if (name != null) {
+ mName = name;
+ mImageResourceId = ActivityTransition.getDrawableIdForKey(name);
+ }
+
+ return getResources().getDrawable(mImageResourceId);
+ }
+
+ public void clicked(View v) {
+ Intent intent = new Intent(this, ActivityTransition.class);
+ intent.putExtra(KEY_ID, mName);
+ ActivityOptions activityOptions = ActivityOptions.makeSceneTransitionAnimation(
+ this, v, "hero");
+ startActivity(intent, activityOptions.toBundle());
+ }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/InflatingListActivity.java b/tests/UiBench/src/com/android/test/uibench/InflatingListActivity.java
index 84383ec9d911..603244eb2a43 100644
--- a/tests/UiBench/src/com/android/test/uibench/InflatingListActivity.java
+++ b/tests/UiBench/src/com/android/test/uibench/InflatingListActivity.java
@@ -20,6 +20,8 @@ import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListAdapter;
+import com.android.test.uibench.listview.CompatListActivity;
+
public class InflatingListActivity extends CompatListActivity {
@Override
protected ListAdapter createListAdapter() {
diff --git a/tests/UiBench/src/com/android/test/uibench/TextCacheHighHitrateActivity.java b/tests/UiBench/src/com/android/test/uibench/TextCacheHighHitrateActivity.java
index 91d74ac580ca..fc5be35be4a3 100644
--- a/tests/UiBench/src/com/android/test/uibench/TextCacheHighHitrateActivity.java
+++ b/tests/UiBench/src/com/android/test/uibench/TextCacheHighHitrateActivity.java
@@ -18,6 +18,8 @@ package com.android.test.uibench;
import android.widget.ArrayAdapter;
import android.widget.ListAdapter;
+import com.android.test.uibench.listview.CompatListActivity;
+
public class TextCacheHighHitrateActivity extends CompatListActivity {
@Override
protected ListAdapter createListAdapter() {
diff --git a/tests/UiBench/src/com/android/test/uibench/TextCacheLowHitrateActivity.java b/tests/UiBench/src/com/android/test/uibench/TextCacheLowHitrateActivity.java
index b526cde9d3b2..14dc437d052b 100644
--- a/tests/UiBench/src/com/android/test/uibench/TextCacheLowHitrateActivity.java
+++ b/tests/UiBench/src/com/android/test/uibench/TextCacheLowHitrateActivity.java
@@ -18,6 +18,8 @@ package com.android.test.uibench;
import android.widget.ArrayAdapter;
import android.widget.ListAdapter;
+import com.android.test.uibench.listview.CompatListActivity;
+
public class TextCacheLowHitrateActivity extends CompatListActivity {
@Override
protected ListAdapter createListAdapter() {
diff --git a/tests/UiBench/src/com/android/test/uibench/TrivialListActivity.java b/tests/UiBench/src/com/android/test/uibench/TrivialListActivity.java
index 339ac80615ee..2625a99f3c82 100644
--- a/tests/UiBench/src/com/android/test/uibench/TrivialListActivity.java
+++ b/tests/UiBench/src/com/android/test/uibench/TrivialListActivity.java
@@ -18,6 +18,8 @@ package com.android.test.uibench;
import android.widget.ArrayAdapter;
import android.widget.ListAdapter;
+import com.android.test.uibench.listview.CompatListActivity;
+
public class TrivialListActivity extends CompatListActivity {
@Override
protected ListAdapter createListAdapter() {
diff --git a/tests/UiBench/src/com/android/test/uibench/TrivialRecyclerViewActivity.java b/tests/UiBench/src/com/android/test/uibench/TrivialRecyclerViewActivity.java
new file mode 100644
index 000000000000..4647ba774b2e
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/TrivialRecyclerViewActivity.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.test.uibench;
+
+import android.support.v7.widget.RecyclerView;
+
+import com.android.test.uibench.recyclerview.RvArrayAdapter;
+import com.android.test.uibench.recyclerview.RvCompatListActivity;
+
+public class TrivialRecyclerViewActivity extends RvCompatListActivity {
+ @Override
+ protected RecyclerView.Adapter createAdapter() {
+ return new RvArrayAdapter(TextUtils.buildSimpleStringList());
+ }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/CompatListActivity.java b/tests/UiBench/src/com/android/test/uibench/listview/CompatListActivity.java
index 40ec4530fbc4..214c07463fd7 100644
--- a/tests/UiBench/src/com/android/test/uibench/CompatListActivity.java
+++ b/tests/UiBench/src/com/android/test/uibench/listview/CompatListActivity.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.test.uibench;
+package com.android.test.uibench.listview;
import android.os.Bundle;
import android.support.v4.app.FragmentManager;
diff --git a/tests/UiBench/src/com/android/test/uibench/recyclerview/RvArrayAdapter.java b/tests/UiBench/src/com/android/test/uibench/recyclerview/RvArrayAdapter.java
new file mode 100644
index 000000000000..e5a3a49cf228
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/recyclerview/RvArrayAdapter.java
@@ -0,0 +1,64 @@
+/*
+ * 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.test.uibench.recyclerview;
+
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+public class RvArrayAdapter extends RecyclerView.Adapter<RvArrayAdapter.ViewHolder> {
+ private String[] mDataSet;
+ private LayoutInflater mLayoutInflater;
+
+ public static class ViewHolder extends RecyclerView.ViewHolder {
+ private final TextView mTextView;
+
+ public ViewHolder(View v) {
+ super(v);
+ mTextView = (TextView) v.findViewById(android.R.id.text1);
+ }
+
+ public TextView getTextView() {
+ return mTextView;
+ }
+ }
+
+ public RvArrayAdapter(String[] dataSet) {
+ mDataSet = dataSet;
+ }
+
+ @Override
+ public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
+ if (mLayoutInflater == null) {
+ mLayoutInflater = LayoutInflater.from(viewGroup.getContext());
+ }
+ View v = mLayoutInflater.inflate(android.R.layout.simple_list_item_1, viewGroup, false);
+
+ return new ViewHolder(v);
+ }
+
+ @Override
+ public void onBindViewHolder(ViewHolder viewHolder, final int position) {
+ viewHolder.getTextView().setText(mDataSet[position]);
+ }
+
+ @Override
+ public int getItemCount() {
+ return mDataSet.length;
+ }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/recyclerview/RvCompatListActivity.java b/tests/UiBench/src/com/android/test/uibench/recyclerview/RvCompatListActivity.java
new file mode 100644
index 000000000000..e08dbc66e7f2
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/recyclerview/RvCompatListActivity.java
@@ -0,0 +1,68 @@
+/*
+ * 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.test.uibench.recyclerview;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+
+import com.android.test.uibench.R;
+
+public abstract class RvCompatListActivity extends AppCompatActivity {
+ public static class RecyclerViewFragment extends Fragment {
+ RecyclerView.LayoutManager layoutManager;
+ RecyclerView.Adapter adapter;
+
+ @Nullable
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ RecyclerView recyclerView = (RecyclerView) inflater.inflate(
+ R.layout.recycler_view, container, false);
+ recyclerView.setLayoutManager(layoutManager);
+ recyclerView.setAdapter(adapter);
+ return recyclerView;
+ }
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ FragmentManager fm = getSupportFragmentManager();
+ if (fm.findFragmentById(android.R.id.content) == null) {
+ RecyclerViewFragment fragment = new RecyclerViewFragment();
+ fragment.layoutManager = createLayoutManager(this);
+ fragment.adapter = createAdapter();
+ fm.beginTransaction().add(android.R.id.content, fragment).commit();
+ }
+ }
+
+ protected RecyclerView.LayoutManager createLayoutManager(Context context) {
+ return new LinearLayoutManager(context);
+ }
+
+ protected abstract RecyclerView.Adapter createAdapter();
+}
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml
index 705cc34ff62b..2be99bed4bfb 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml
@@ -21,10 +21,14 @@
<group>
<path
+ android:name="box0"
+ android:pathData="m0,0l480,0l0,480l-480,0l0-480z"
+ android:fillColor="@android:color/white" />
+ <path
android:name="box1"
android:pathData="m20,200l100,90l180-180l-35-35l-145,145l-60-60l-40,40z"
- android:fillColor="?android:attr/colorControlActivated"
- android:strokeColor="?android:attr/colorControlActivated"
+ android:fillColor="?android:attr/colorControlNormal"
+ android:strokeColor="?android:attr/colorControlNormal"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawable01.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawable01.java
index a23d81933749..85fc452add3e 100644
--- a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawable01.java
+++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawable01.java
@@ -18,7 +18,12 @@ import android.graphics.drawable.VectorDrawable;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
import android.widget.Button;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.GridLayout;
@SuppressWarnings({"UnusedDeclaration"})
@@ -55,6 +60,23 @@ public class VectorDrawable01 extends Activity {
container.setBackgroundColor(0xFF888888);
final Button []bArray = new Button[icon.length];
+ CheckBox toggle = new CheckBox(this);
+ toggle.setText("Toggle");
+ toggle.setChecked(true);
+ toggle.setOnCheckedChangeListener(new OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ ViewGroup vg = (ViewGroup) buttonView.getParent();
+ for (int i = 0, count = vg.getChildCount(); i < count; i++) {
+ View child = vg.getChildAt(i);
+ if (child != buttonView) {
+ child.setEnabled(isChecked);
+ }
+ }
+ }
+ });
+ container.addView(toggle);
+
for (int i = 0; i < icon.length; i++) {
Button button = new Button(this);
bArray[i] = button;
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 0f959ea0f921..a390b0cab321 100644
--- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
@@ -94,7 +94,7 @@ public class WindowManagerPermissionTests extends TestCase {
try {
mWm.addAppToken(0, null, 0, 0, 0, false, false, 0, 0, false, false, null,
- Configuration.EMPTY);
+ Configuration.EMPTY, false);
fail("IWindowManager.addAppToken did not throw SecurityException as"
+ " expected");
} catch (SecurityException e) {
diff --git a/tools/aapt2/Logger.h b/tools/aapt2/Logger.h
index 1d437ebe6492..eed58b83ffc4 100644
--- a/tools/aapt2/Logger.h
+++ b/tools/aapt2/Logger.h
@@ -18,11 +18,11 @@
#define AAPT_LOGGER_H
#include "Source.h"
+#include "StringPiece.h"
#include <memory>
#include <ostream>
#include <string>
-#include <utils/String8.h>
namespace aapt {
@@ -71,11 +71,6 @@ private:
Source mSource;
};
-inline ::std::ostream& operator<<(::std::ostream& out, const std::u16string& str) {
- android::String8 utf8(str.data(), str.size());
- return out.write(utf8.string(), utf8.size());
-}
-
} // namespace aapt
#endif // AAPT_LOGGER_H
diff --git a/tools/aapt2/StringPiece.h b/tools/aapt2/StringPiece.h
index e2a1597caeda..8cbdeae5e892 100644
--- a/tools/aapt2/StringPiece.h
+++ b/tools/aapt2/StringPiece.h
@@ -229,4 +229,9 @@ inline ::std::ostream& operator<<(::std::ostream& out, const BasicStringPiece<ch
} // namespace aapt
+inline ::std::ostream& operator<<(::std::ostream& out, const std::u16string& str) {
+ android::String8 utf8(str.data(), str.size());
+ return out.write(utf8.string(), utf8.size());
+}
+
#endif // AAPT_STRING_PIECE_H
diff --git a/tools/aapt2/Util.cpp b/tools/aapt2/Util.cpp
index 03ecd1aca310..ca352e0e9b61 100644
--- a/tools/aapt2/Util.cpp
+++ b/tools/aapt2/Util.cpp
@@ -175,7 +175,51 @@ StringBuilder& StringBuilder::append(const StringPiece16& str) {
const char16_t* start = str.begin();
const char16_t* current = start;
while (current != end) {
- if (*current == u'"') {
+ if (mLastCharWasEscape) {
+ switch (*current) {
+ case u't':
+ mStr += u'\t';
+ break;
+ case u'n':
+ mStr += u'\n';
+ break;
+ case u'#':
+ mStr += u'#';
+ break;
+ case u'@':
+ mStr += u'@';
+ break;
+ case u'?':
+ mStr += u'?';
+ break;
+ case u'"':
+ mStr += u'"';
+ break;
+ case u'\'':
+ mStr += u'\'';
+ break;
+ case u'\\':
+ mStr += u'\\';
+ break;
+ case u'u': {
+ current++;
+ Maybe<char16_t> c = parseUnicodeCodepoint(&current, end);
+ if (!c) {
+ mError = "invalid unicode escape sequence";
+ return *this;
+ }
+ mStr += c.value();
+ current -= 1;
+ break;
+ }
+
+ default:
+ // Ignore.
+ break;
+ }
+ mLastCharWasEscape = false;
+ start = current + 1;
+ } else if (*current == u'"') {
if (!mQuote && mTrailingSpace) {
// We found an opening quote, and we have
// trailing space, so we should append that
@@ -208,52 +252,7 @@ StringBuilder& StringBuilder::append(const StringPiece16& str) {
}
mStr.append(start, current - start);
start = current + 1;
-
- current++;
- if (current != end) {
- switch (*current) {
- case u't':
- mStr += u'\t';
- break;
- case u'n':
- mStr += u'\n';
- break;
- case u'#':
- mStr += u'#';
- break;
- case u'@':
- mStr += u'@';
- break;
- case u'?':
- mStr += u'?';
- break;
- case u'"':
- mStr += u'"';
- break;
- case u'\'':
- mStr += u'\'';
- break;
- case u'\\':
- mStr += u'\\';
- break;
- case u'u': {
- current++;
- Maybe<char16_t> c = parseUnicodeCodepoint(&current, end);
- if (!c) {
- mError = "invalid unicode escape sequence";
- return *this;
- }
- mStr += c.value();
- current -= 1;
- break;
- }
-
- default:
- // Ignore.
- break;
- }
- start = current + 1;
- }
+ mLastCharWasEscape = true;
} else if (!mQuote) {
// This is not quoted text, so look for whitespace.
if (isspace16(*current)) {
diff --git a/tools/aapt2/Util.h b/tools/aapt2/Util.h
index 9cdb152bf41f..7ec6b030fd85 100644
--- a/tools/aapt2/Util.h
+++ b/tools/aapt2/Util.h
@@ -162,6 +162,7 @@ private:
std::u16string mStr;
bool mQuote = false;
bool mTrailingSpace = false;
+ bool mLastCharWasEscape = false;
std::string mError;
};
diff --git a/tools/aapt2/Util_test.cpp b/tools/aapt2/Util_test.cpp
index 0b08d240cad3..92f2a1c0f1d1 100644
--- a/tools/aapt2/Util_test.cpp
+++ b/tools/aapt2/Util_test.cpp
@@ -38,6 +38,13 @@ TEST(UtilTest, StringStartsWith) {
EXPECT_TRUE(util::stringStartsWith<char>("hello.xml", "he"));
}
+TEST(UtilTest, StringBuilderSplitEscapeSequence) {
+ EXPECT_EQ(StringPiece16(u"this is a new\nline."),
+ util::StringBuilder().append(u"this is a new\\")
+ .append(u"nline.")
+ .str());
+}
+
TEST(UtilTest, StringBuilderWhitespaceRemoval) {
EXPECT_EQ(StringPiece16(u"hey guys this is so cool"),
util::StringBuilder().append(u" hey guys ")
diff --git a/tools/aidl b/tools/aidl
new file mode 100644
index 000000000000..8a42fa0d0a35
--- /dev/null
+++ b/tools/aidl
@@ -0,0 +1,4 @@
+Where has aidl gone?
+
+ aidl has moved to //system/tools/aidl as part of adding support for
+ generating bindings in C++.
diff --git a/tools/aidl/AST.cpp b/tools/aidl/AST.cpp
deleted file mode 100644
index bfa67656b323..000000000000
--- a/tools/aidl/AST.cpp
+++ /dev/null
@@ -1,912 +0,0 @@
-#include "AST.h"
-#include "Type.h"
-
-void
-WriteModifiers(FILE* to, int mod, int mask)
-{
- int m = mod & mask;
-
- if (m & OVERRIDE) {
- fprintf(to, "@Override ");
- }
-
- if ((m & SCOPE_MASK) == PUBLIC) {
- fprintf(to, "public ");
- }
- else if ((m & SCOPE_MASK) == PRIVATE) {
- fprintf(to, "private ");
- }
- else if ((m & SCOPE_MASK) == PROTECTED) {
- fprintf(to, "protected ");
- }
-
- if (m & STATIC) {
- fprintf(to, "static ");
- }
-
- if (m & FINAL) {
- fprintf(to, "final ");
- }
-
- if (m & ABSTRACT) {
- fprintf(to, "abstract ");
- }
-}
-
-void
-WriteArgumentList(FILE* to, const vector<Expression*>& arguments)
-{
- size_t N = arguments.size();
- for (size_t i=0; i<N; i++) {
- arguments[i]->Write(to);
- if (i != N-1) {
- fprintf(to, ", ");
- }
- }
-}
-
-ClassElement::ClassElement()
-{
-}
-
-ClassElement::~ClassElement()
-{
-}
-
-Field::Field()
- :ClassElement(),
- modifiers(0),
- variable(NULL)
-{
-}
-
-Field::Field(int m, Variable* v)
- :ClassElement(),
- modifiers(m),
- variable(v)
-{
-}
-
-Field::~Field()
-{
-}
-
-void
-Field::GatherTypes(set<Type*>* types) const
-{
- types->insert(this->variable->type);
-}
-
-void
-Field::Write(FILE* to)
-{
- if (this->comment.length() != 0) {
- fprintf(to, "%s\n", this->comment.c_str());
- }
- WriteModifiers(to, this->modifiers, SCOPE_MASK | STATIC | FINAL | OVERRIDE);
- fprintf(to, "%s %s", this->variable->type->QualifiedName().c_str(),
- this->variable->name.c_str());
- if (this->value.length() != 0) {
- fprintf(to, " = %s", this->value.c_str());
- }
- fprintf(to, ";\n");
-}
-
-Expression::~Expression()
-{
-}
-
-LiteralExpression::LiteralExpression(const string& v)
- :value(v)
-{
-}
-
-LiteralExpression::~LiteralExpression()
-{
-}
-
-void
-LiteralExpression::Write(FILE* to)
-{
- fprintf(to, "%s", this->value.c_str());
-}
-
-StringLiteralExpression::StringLiteralExpression(const string& v)
- :value(v)
-{
-}
-
-StringLiteralExpression::~StringLiteralExpression()
-{
-}
-
-void
-StringLiteralExpression::Write(FILE* to)
-{
- fprintf(to, "\"%s\"", this->value.c_str());
-}
-
-Variable::Variable()
- :type(NULL),
- name(),
- dimension(0)
-{
-}
-
-Variable::Variable(Type* t, const string& n)
- :type(t),
- name(n),
- dimension(0)
-{
-}
-
-Variable::Variable(Type* t, const string& n, int d)
- :type(t),
- name(n),
- dimension(d)
-{
-}
-
-Variable::~Variable()
-{
-}
-
-void
-Variable::GatherTypes(set<Type*>* types) const
-{
- types->insert(this->type);
-}
-
-void
-Variable::WriteDeclaration(FILE* to)
-{
- string dim;
- for (int i=0; i<this->dimension; i++) {
- dim += "[]";
- }
- fprintf(to, "%s%s %s", this->type->QualifiedName().c_str(), dim.c_str(),
- this->name.c_str());
-}
-
-void
-Variable::Write(FILE* to)
-{
- fprintf(to, "%s", name.c_str());
-}
-
-FieldVariable::FieldVariable(Expression* o, const string& n)
- :object(o),
- clazz(NULL),
- name(n)
-{
-}
-
-FieldVariable::FieldVariable(Type* c, const string& n)
- :object(NULL),
- clazz(c),
- name(n)
-{
-}
-
-FieldVariable::~FieldVariable()
-{
-}
-
-void
-FieldVariable::Write(FILE* to)
-{
- if (this->object != NULL) {
- this->object->Write(to);
- }
- else if (this->clazz != NULL) {
- fprintf(to, "%s", this->clazz->QualifiedName().c_str());
- }
- fprintf(to, ".%s", name.c_str());
-}
-
-
-Statement::~Statement()
-{
-}
-
-StatementBlock::StatementBlock()
-{
-}
-
-StatementBlock::~StatementBlock()
-{
-}
-
-void
-StatementBlock::Write(FILE* to)
-{
- fprintf(to, "{\n");
- int N = this->statements.size();
- for (int i=0; i<N; i++) {
- this->statements[i]->Write(to);
- }
- fprintf(to, "}\n");
-}
-
-void
-StatementBlock::Add(Statement* statement)
-{
- this->statements.push_back(statement);
-}
-
-void
-StatementBlock::Add(Expression* expression)
-{
- this->statements.push_back(new ExpressionStatement(expression));
-}
-
-ExpressionStatement::ExpressionStatement(Expression* e)
- :expression(e)
-{
-}
-
-ExpressionStatement::~ExpressionStatement()
-{
-}
-
-void
-ExpressionStatement::Write(FILE* to)
-{
- this->expression->Write(to);
- fprintf(to, ";\n");
-}
-
-Assignment::Assignment(Variable* l, Expression* r)
- :lvalue(l),
- rvalue(r),
- cast(NULL)
-{
-}
-
-Assignment::Assignment(Variable* l, Expression* r, Type* c)
- :lvalue(l),
- rvalue(r),
- cast(c)
-{
-}
-
-Assignment::~Assignment()
-{
-}
-
-void
-Assignment::Write(FILE* to)
-{
- this->lvalue->Write(to);
- fprintf(to, " = ");
- if (this->cast != NULL) {
- fprintf(to, "(%s)", this->cast->QualifiedName().c_str());
- }
- this->rvalue->Write(to);
-}
-
-MethodCall::MethodCall(const string& n)
- :obj(NULL),
- clazz(NULL),
- name(n)
-{
-}
-
-MethodCall::MethodCall(const string& n, int argc = 0, ...)
- :obj(NULL),
- clazz(NULL),
- name(n)
-{
- va_list args;
- va_start(args, argc);
- init(argc, args);
- va_end(args);
-}
-
-MethodCall::MethodCall(Expression* o, const string& n)
- :obj(o),
- clazz(NULL),
- name(n)
-{
-}
-
-MethodCall::MethodCall(Type* t, const string& n)
- :obj(NULL),
- clazz(t),
- name(n)
-{
-}
-
-MethodCall::MethodCall(Expression* o, const string& n, int argc = 0, ...)
- :obj(o),
- clazz(NULL),
- name(n)
-{
- va_list args;
- va_start(args, argc);
- init(argc, args);
- va_end(args);
-}
-
-MethodCall::MethodCall(Type* t, const string& n, int argc = 0, ...)
- :obj(NULL),
- clazz(t),
- name(n)
-{
- va_list args;
- va_start(args, argc);
- init(argc, args);
- va_end(args);
-}
-
-MethodCall::~MethodCall()
-{
-}
-
-void
-MethodCall::init(int n, va_list args)
-{
- for (int i=0; i<n; i++) {
- Expression* expression = (Expression*)va_arg(args, void*);
- this->arguments.push_back(expression);
- }
-}
-
-void
-MethodCall::Write(FILE* to)
-{
- if (this->obj != NULL) {
- this->obj->Write(to);
- fprintf(to, ".");
- }
- else if (this->clazz != NULL) {
- fprintf(to, "%s.", this->clazz->QualifiedName().c_str());
- }
- fprintf(to, "%s(", this->name.c_str());
- WriteArgumentList(to, this->arguments);
- fprintf(to, ")");
-}
-
-Comparison::Comparison(Expression* l, const string& o, Expression* r)
- :lvalue(l),
- op(o),
- rvalue(r)
-{
-}
-
-Comparison::~Comparison()
-{
-}
-
-void
-Comparison::Write(FILE* to)
-{
- fprintf(to, "(");
- this->lvalue->Write(to);
- fprintf(to, "%s", this->op.c_str());
- this->rvalue->Write(to);
- fprintf(to, ")");
-}
-
-NewExpression::NewExpression(Type* t)
- :type(t)
-{
-}
-
-NewExpression::NewExpression(Type* t, int argc = 0, ...)
- :type(t)
-{
- va_list args;
- va_start(args, argc);
- init(argc, args);
- va_end(args);
-}
-
-NewExpression::~NewExpression()
-{
-}
-
-void
-NewExpression::init(int n, va_list args)
-{
- for (int i=0; i<n; i++) {
- Expression* expression = (Expression*)va_arg(args, void*);
- this->arguments.push_back(expression);
- }
-}
-
-void
-NewExpression::Write(FILE* to)
-{
- fprintf(to, "new %s(", this->type->InstantiableName().c_str());
- WriteArgumentList(to, this->arguments);
- fprintf(to, ")");
-}
-
-NewArrayExpression::NewArrayExpression(Type* t, Expression* s)
- :type(t),
- size(s)
-{
-}
-
-NewArrayExpression::~NewArrayExpression()
-{
-}
-
-void
-NewArrayExpression::Write(FILE* to)
-{
- fprintf(to, "new %s[", this->type->QualifiedName().c_str());
- size->Write(to);
- fprintf(to, "]");
-}
-
-Ternary::Ternary()
- :condition(NULL),
- ifpart(NULL),
- elsepart(NULL)
-{
-}
-
-Ternary::Ternary(Expression* a, Expression* b, Expression* c)
- :condition(a),
- ifpart(b),
- elsepart(c)
-{
-}
-
-Ternary::~Ternary()
-{
-}
-
-void
-Ternary::Write(FILE* to)
-{
- fprintf(to, "((");
- this->condition->Write(to);
- fprintf(to, ")?(");
- this->ifpart->Write(to);
- fprintf(to, "):(");
- this->elsepart->Write(to);
- fprintf(to, "))");
-}
-
-Cast::Cast()
- :type(NULL),
- expression(NULL)
-{
-}
-
-Cast::Cast(Type* t, Expression* e)
- :type(t),
- expression(e)
-{
-}
-
-Cast::~Cast()
-{
-}
-
-void
-Cast::Write(FILE* to)
-{
- fprintf(to, "((%s)", this->type->QualifiedName().c_str());
- expression->Write(to);
- fprintf(to, ")");
-}
-
-VariableDeclaration::VariableDeclaration(Variable* l, Expression* r, Type* c)
- :lvalue(l),
- cast(c),
- rvalue(r)
-{
-}
-
-VariableDeclaration::VariableDeclaration(Variable* l)
- :lvalue(l),
- cast(NULL),
- rvalue(NULL)
-{
-}
-
-VariableDeclaration::~VariableDeclaration()
-{
-}
-
-void
-VariableDeclaration::Write(FILE* to)
-{
- this->lvalue->WriteDeclaration(to);
- if (this->rvalue != NULL) {
- fprintf(to, " = ");
- if (this->cast != NULL) {
- fprintf(to, "(%s)", this->cast->QualifiedName().c_str());
- }
- this->rvalue->Write(to);
- }
- fprintf(to, ";\n");
-}
-
-IfStatement::IfStatement()
- :expression(NULL),
- statements(new StatementBlock),
- elseif(NULL)
-{
-}
-
-IfStatement::~IfStatement()
-{
-}
-
-void
-IfStatement::Write(FILE* to)
-{
- if (this->expression != NULL) {
- fprintf(to, "if (");
- this->expression->Write(to);
- fprintf(to, ") ");
- }
- this->statements->Write(to);
- if (this->elseif != NULL) {
- fprintf(to, "else ");
- this->elseif->Write(to);
- }
-}
-
-ReturnStatement::ReturnStatement(Expression* e)
- :expression(e)
-{
-}
-
-ReturnStatement::~ReturnStatement()
-{
-}
-
-void
-ReturnStatement::Write(FILE* to)
-{
- fprintf(to, "return ");
- this->expression->Write(to);
- fprintf(to, ";\n");
-}
-
-TryStatement::TryStatement()
- :statements(new StatementBlock)
-{
-}
-
-TryStatement::~TryStatement()
-{
-}
-
-void
-TryStatement::Write(FILE* to)
-{
- fprintf(to, "try ");
- this->statements->Write(to);
-}
-
-CatchStatement::CatchStatement(Variable* e)
- :statements(new StatementBlock),
- exception(e)
-{
-}
-
-CatchStatement::~CatchStatement()
-{
-}
-
-void
-CatchStatement::Write(FILE* to)
-{
- fprintf(to, "catch ");
- if (this->exception != NULL) {
- fprintf(to, "(");
- this->exception->WriteDeclaration(to);
- fprintf(to, ") ");
- }
- this->statements->Write(to);
-}
-
-FinallyStatement::FinallyStatement()
- :statements(new StatementBlock)
-{
-}
-
-FinallyStatement::~FinallyStatement()
-{
-}
-
-void
-FinallyStatement::Write(FILE* to)
-{
- fprintf(to, "finally ");
- this->statements->Write(to);
-}
-
-Case::Case()
- :statements(new StatementBlock)
-{
-}
-
-Case::Case(const string& c)
- :statements(new StatementBlock)
-{
- cases.push_back(c);
-}
-
-Case::~Case()
-{
-}
-
-void
-Case::Write(FILE* to)
-{
- int N = this->cases.size();
- if (N > 0) {
- for (int i=0; i<N; i++) {
- string s = this->cases[i];
- if (s.length() != 0) {
- fprintf(to, "case %s:\n", s.c_str());
- } else {
- fprintf(to, "default:\n");
- }
- }
- } else {
- fprintf(to, "default:\n");
- }
- statements->Write(to);
-}
-
-SwitchStatement::SwitchStatement(Expression* e)
- :expression(e)
-{
-}
-
-SwitchStatement::~SwitchStatement()
-{
-}
-
-void
-SwitchStatement::Write(FILE* to)
-{
- fprintf(to, "switch (");
- this->expression->Write(to);
- fprintf(to, ")\n{\n");
- int N = this->cases.size();
- for (int i=0; i<N; i++) {
- this->cases[i]->Write(to);
- }
- fprintf(to, "}\n");
-}
-
-Break::Break()
-{
-}
-
-Break::~Break()
-{
-}
-
-void
-Break::Write(FILE* to)
-{
- fprintf(to, "break;\n");
-}
-
-Method::Method()
- :ClassElement(),
- modifiers(0),
- returnType(NULL), // (NULL means constructor)
- returnTypeDimension(0),
- statements(NULL)
-{
-}
-
-Method::~Method()
-{
-}
-
-void
-Method::GatherTypes(set<Type*>* types) const
-{
- size_t N, i;
-
- if (this->returnType) {
- types->insert(this->returnType);
- }
-
- N = this->parameters.size();
- for (i=0; i<N; i++) {
- this->parameters[i]->GatherTypes(types);
- }
-
- N = this->exceptions.size();
- for (i=0; i<N; i++) {
- types->insert(this->exceptions[i]);
- }
-}
-
-void
-Method::Write(FILE* to)
-{
- size_t N, i;
-
- if (this->comment.length() != 0) {
- fprintf(to, "%s\n", this->comment.c_str());
- }
-
- WriteModifiers(to, this->modifiers, SCOPE_MASK | STATIC | ABSTRACT | FINAL | OVERRIDE);
-
- if (this->returnType != NULL) {
- string dim;
- for (i=0; i<this->returnTypeDimension; i++) {
- dim += "[]";
- }
- fprintf(to, "%s%s ", this->returnType->QualifiedName().c_str(),
- dim.c_str());
- }
-
- fprintf(to, "%s(", this->name.c_str());
-
- N = this->parameters.size();
- for (i=0; i<N; i++) {
- this->parameters[i]->WriteDeclaration(to);
- if (i != N-1) {
- fprintf(to, ", ");
- }
- }
-
- fprintf(to, ")");
-
- N = this->exceptions.size();
- for (i=0; i<N; i++) {
- if (i == 0) {
- fprintf(to, " throws ");
- } else {
- fprintf(to, ", ");
- }
- fprintf(to, "%s", this->exceptions[i]->QualifiedName().c_str());
- }
-
- if (this->statements == NULL) {
- fprintf(to, ";\n");
- } else {
- fprintf(to, "\n");
- this->statements->Write(to);
- }
-}
-
-Class::Class()
- :modifiers(0),
- what(CLASS),
- type(NULL),
- extends(NULL)
-{
-}
-
-Class::~Class()
-{
-}
-
-void
-Class::GatherTypes(set<Type*>* types) const
-{
- int N, i;
-
- types->insert(this->type);
- if (this->extends != NULL) {
- types->insert(this->extends);
- }
-
- N = this->interfaces.size();
- for (i=0; i<N; i++) {
- types->insert(this->interfaces[i]);
- }
-
- N = this->elements.size();
- for (i=0; i<N; i++) {
- this->elements[i]->GatherTypes(types);
- }
-}
-
-void
-Class::Write(FILE* to)
-{
- size_t N, i;
-
- if (this->comment.length() != 0) {
- fprintf(to, "%s\n", this->comment.c_str());
- }
-
- WriteModifiers(to, this->modifiers, ALL_MODIFIERS);
-
- if (this->what == Class::CLASS) {
- fprintf(to, "class ");
- } else {
- fprintf(to, "interface ");
- }
-
- string name = this->type->Name();
- size_t pos = name.rfind('.');
- if (pos != string::npos) {
- name = name.c_str() + pos + 1;
- }
-
- fprintf(to, "%s", name.c_str());
-
- if (this->extends != NULL) {
- fprintf(to, " extends %s", this->extends->QualifiedName().c_str());
- }
-
- N = this->interfaces.size();
- if (N != 0) {
- if (this->what == Class::CLASS) {
- fprintf(to, " implements");
- } else {
- fprintf(to, " extends");
- }
- for (i=0; i<N; i++) {
- fprintf(to, " %s", this->interfaces[i]->QualifiedName().c_str());
- }
- }
-
- fprintf(to, "\n");
- fprintf(to, "{\n");
-
- N = this->elements.size();
- for (i=0; i<N; i++) {
- this->elements[i]->Write(to);
- }
-
- fprintf(to, "}\n");
-
-}
-
-Document::Document()
-{
-}
-
-Document::~Document()
-{
-}
-
-static string
-escape_backslashes(const string& str)
-{
- string result;
- const size_t I=str.length();
- for (size_t i=0; i<I; i++) {
- char c = str[i];
- if (c == '\\') {
- result += "\\\\";
- } else {
- result += c;
- }
- }
- return result;
-}
-
-void
-Document::Write(FILE* to)
-{
- size_t N, i;
-
- if (this->comment.length() != 0) {
- fprintf(to, "%s\n", this->comment.c_str());
- }
- fprintf(to, "/*\n"
- " * This file is auto-generated. DO NOT MODIFY.\n"
- " * Original file: %s\n"
- " */\n", escape_backslashes(this->originalSrc).c_str());
- if (this->package.length() != 0) {
- fprintf(to, "package %s;\n", this->package.c_str());
- }
-
- N = this->classes.size();
- for (i=0; i<N; i++) {
- Class* c = this->classes[i];
- c->Write(to);
- }
-}
-
diff --git a/tools/aidl/AST.h b/tools/aidl/AST.h
deleted file mode 100644
index d7bfccb7a6ce..000000000000
--- a/tools/aidl/AST.h
+++ /dev/null
@@ -1,371 +0,0 @@
-#ifndef AIDL_AST_H_
-#define AIDL_AST_H_
-
-#include <string>
-#include <vector>
-#include <set>
-#include <stdarg.h>
-#include <stdio.h>
-
-using namespace std;
-
-class Type;
-
-enum {
- PACKAGE_PRIVATE = 0x00000000,
- PUBLIC = 0x00000001,
- PRIVATE = 0x00000002,
- PROTECTED = 0x00000003,
- SCOPE_MASK = 0x00000003,
-
- STATIC = 0x00000010,
- FINAL = 0x00000020,
- ABSTRACT = 0x00000040,
-
- OVERRIDE = 0x00000100,
-
- ALL_MODIFIERS = 0xffffffff
-};
-
-// Write the modifiers that are set in both mod and mask
-void WriteModifiers(FILE* to, int mod, int mask);
-
-struct ClassElement
-{
- ClassElement();
- virtual ~ClassElement();
-
- virtual void GatherTypes(set<Type*>* types) const = 0;
- virtual void Write(FILE* to) = 0;
-};
-
-struct Expression
-{
- virtual ~Expression();
- virtual void Write(FILE* to) = 0;
-};
-
-struct LiteralExpression : public Expression
-{
- string value;
-
- LiteralExpression(const string& value);
- virtual ~LiteralExpression();
- virtual void Write(FILE* to);
-};
-
-// TODO: also escape the contents. not needed for now
-struct StringLiteralExpression : public Expression
-{
- string value;
-
- StringLiteralExpression(const string& value);
- virtual ~StringLiteralExpression();
- virtual void Write(FILE* to);
-};
-
-struct Variable : public Expression
-{
- Type* type;
- string name;
- int dimension;
-
- Variable();
- Variable(Type* type, const string& name);
- Variable(Type* type, const string& name, int dimension);
- virtual ~Variable();
-
- virtual void GatherTypes(set<Type*>* types) const;
- void WriteDeclaration(FILE* to);
- void Write(FILE* to);
-};
-
-struct FieldVariable : public Expression
-{
- Expression* object;
- Type* clazz;
- string name;
-
- FieldVariable(Expression* object, const string& name);
- FieldVariable(Type* clazz, const string& name);
- virtual ~FieldVariable();
-
- void Write(FILE* to);
-};
-
-struct Field : public ClassElement
-{
- string comment;
- int modifiers;
- Variable *variable;
- string value;
-
- Field();
- Field(int modifiers, Variable* variable);
- virtual ~Field();
-
- virtual void GatherTypes(set<Type*>* types) const;
- virtual void Write(FILE* to);
-};
-
-struct Statement
-{
- virtual ~Statement();
- virtual void Write(FILE* to) = 0;
-};
-
-struct StatementBlock : public Statement
-{
- vector<Statement*> statements;
-
- StatementBlock();
- virtual ~StatementBlock();
- virtual void Write(FILE* to);
-
- void Add(Statement* statement);
- void Add(Expression* expression);
-};
-
-struct ExpressionStatement : public Statement
-{
- Expression* expression;
-
- ExpressionStatement(Expression* expression);
- virtual ~ExpressionStatement();
- virtual void Write(FILE* to);
-};
-
-struct Assignment : public Expression
-{
- Variable* lvalue;
- Expression* rvalue;
- Type* cast;
-
- Assignment(Variable* lvalue, Expression* rvalue);
- Assignment(Variable* lvalue, Expression* rvalue, Type* cast);
- virtual ~Assignment();
- virtual void Write(FILE* to);
-};
-
-struct MethodCall : public Expression
-{
- Expression* obj;
- Type* clazz;
- string name;
- vector<Expression*> arguments;
- vector<string> exceptions;
-
- MethodCall(const string& name);
- MethodCall(const string& name, int argc, ...);
- MethodCall(Expression* obj, const string& name);
- MethodCall(Type* clazz, const string& name);
- MethodCall(Expression* obj, const string& name, int argc, ...);
- MethodCall(Type* clazz, const string& name, int argc, ...);
- virtual ~MethodCall();
- virtual void Write(FILE* to);
-
-private:
- void init(int n, va_list args);
-};
-
-struct Comparison : public Expression
-{
- Expression* lvalue;
- string op;
- Expression* rvalue;
-
- Comparison(Expression* lvalue, const string& op, Expression* rvalue);
- virtual ~Comparison();
- virtual void Write(FILE* to);
-};
-
-struct NewExpression : public Expression
-{
- Type* type;
- vector<Expression*> arguments;
-
- NewExpression(Type* type);
- NewExpression(Type* type, int argc, ...);
- virtual ~NewExpression();
- virtual void Write(FILE* to);
-
-private:
- void init(int n, va_list args);
-};
-
-struct NewArrayExpression : public Expression
-{
- Type* type;
- Expression* size;
-
- NewArrayExpression(Type* type, Expression* size);
- virtual ~NewArrayExpression();
- virtual void Write(FILE* to);
-};
-
-struct Ternary : public Expression
-{
- Expression* condition;
- Expression* ifpart;
- Expression* elsepart;
-
- Ternary();
- Ternary(Expression* condition, Expression* ifpart, Expression* elsepart);
- virtual ~Ternary();
- virtual void Write(FILE* to);
-};
-
-struct Cast : public Expression
-{
- Type* type;
- Expression* expression;
-
- Cast();
- Cast(Type* type, Expression* expression);
- virtual ~Cast();
- virtual void Write(FILE* to);
-};
-
-struct VariableDeclaration : public Statement
-{
- Variable* lvalue;
- Type* cast;
- Expression* rvalue;
-
- VariableDeclaration(Variable* lvalue);
- VariableDeclaration(Variable* lvalue, Expression* rvalue, Type* cast = NULL);
- virtual ~VariableDeclaration();
- virtual void Write(FILE* to);
-};
-
-struct IfStatement : public Statement
-{
- Expression* expression;
- StatementBlock* statements;
- IfStatement* elseif;
-
- IfStatement();
- virtual ~IfStatement();
- virtual void Write(FILE* to);
-};
-
-struct ReturnStatement : public Statement
-{
- Expression* expression;
-
- ReturnStatement(Expression* expression);
- virtual ~ReturnStatement();
- virtual void Write(FILE* to);
-};
-
-struct TryStatement : public Statement
-{
- StatementBlock* statements;
-
- TryStatement();
- virtual ~TryStatement();
- virtual void Write(FILE* to);
-};
-
-struct CatchStatement : public Statement
-{
- StatementBlock* statements;
- Variable* exception;
-
- CatchStatement(Variable* exception);
- virtual ~CatchStatement();
- virtual void Write(FILE* to);
-};
-
-struct FinallyStatement : public Statement
-{
- StatementBlock* statements;
-
- FinallyStatement();
- virtual ~FinallyStatement();
- virtual void Write(FILE* to);
-};
-
-struct Case
-{
- vector<string> cases;
- StatementBlock* statements;
-
- Case();
- Case(const string& c);
- virtual ~Case();
- virtual void Write(FILE* to);
-};
-
-struct SwitchStatement : public Statement
-{
- Expression* expression;
- vector<Case*> cases;
-
- SwitchStatement(Expression* expression);
- virtual ~SwitchStatement();
- virtual void Write(FILE* to);
-};
-
-struct Break : public Statement
-{
- Break();
- virtual ~Break();
- virtual void Write(FILE* to);
-};
-
-struct Method : public ClassElement
-{
- string comment;
- int modifiers;
- Type* returnType;
- size_t returnTypeDimension;
- string name;
- vector<Variable*> parameters;
- vector<Type*> exceptions;
- StatementBlock* statements;
-
- Method();
- virtual ~Method();
-
- virtual void GatherTypes(set<Type*>* types) const;
- virtual void Write(FILE* to);
-};
-
-struct Class : public ClassElement
-{
- enum {
- CLASS,
- INTERFACE
- };
-
- string comment;
- int modifiers;
- int what; // CLASS or INTERFACE
- Type* type;
- Type* extends;
- vector<Type*> interfaces;
- vector<ClassElement*> elements;
-
- Class();
- virtual ~Class();
-
- virtual void GatherTypes(set<Type*>* types) const;
- virtual void Write(FILE* to);
-};
-
-struct Document
-{
- string comment;
- string package;
- string originalSrc;
- set<Type*> imports;
- vector<Class*> classes;
-
- Document();
- virtual ~Document();
-
- virtual void Write(FILE* to);
-};
-
-#endif // AIDL_AST_H_
diff --git a/tools/aidl/Android.mk b/tools/aidl/Android.mk
deleted file mode 100644
index d11264e7da5e..000000000000
--- a/tools/aidl/Android.mk
+++ /dev/null
@@ -1,80 +0,0 @@
-# Copyright 2007 The Android Open Source Project
-#
-# Copies files into the directory structure described by a manifest
-
-# This tool is prebuilt if we're doing an app-only build.
-ifeq ($(TARGET_BUILD_APPS)$(filter true,$(TARGET_BUILD_PDK)),)
-
-LOCAL_PATH:= $(call my-dir)
-
-# Logic shared between aidl and its unittests
-include $(CLEAR_VARS)
-LOCAL_MODULE := libaidl-common
-LOCAL_MODULE_HOST_OS := darwin linux windows
-
-LOCAL_CLANG_CFLAGS := -Wall -Werror
-# Tragically, the code is riddled with unused parameters.
-LOCAL_CLANG_CFLAGS += -Wno-unused-parameter
-# yacc dumps a lot of code *just in case*.
-LOCAL_CLANG_CFLAGS += -Wno-unused-function
-LOCAL_CLANG_CFLAGS += -Wno-unneeded-internal-declaration
-# yacc is a tool from a more civilized age.
-LOCAL_CLANG_CFLAGS += -Wno-deprecated-register
-# yacc also has a habit of using char* over const char*.
-LOCAL_CLANG_CFLAGS += -Wno-writable-strings
-
-LOCAL_SRC_FILES := \
- AST.cpp \
- Type.cpp \
- aidl.cpp \
- aidl_language.cpp \
- aidl_language_l.l \
- aidl_language_y.y \
- generate_java.cpp \
- generate_java_binder.cpp \
- options.cpp \
- search_path.cpp \
-
-include $(BUILD_HOST_STATIC_LIBRARY)
-
-
-# aidl executable
-include $(CLEAR_VARS)
-LOCAL_MODULE := aidl
-
-LOCAL_MODULE_HOST_OS := darwin linux windows
-LOCAL_CFLAGS := -Wall -Werror
-LOCAL_SRC_FILES := main.cpp
-LOCAL_STATIC_LIBRARIES := libaidl-common
-include $(BUILD_HOST_EXECUTABLE)
-
-
-# TODO(wiley) Compile these for mac as well after b/22771504
-ifeq ($(HOST_OS),linux)
-# Unit tests
-include $(CLEAR_VARS)
-LOCAL_MODULE := aidl_unittests
-
-LOCAL_CFLAGS := -g -DUNIT_TEST -Wall -Werror
-# Tragically, the code is riddled with unused parameters.
-LOCAL_CLANG_CFLAGS := -Wno-unused-parameter
-LOCAL_SRC_FILES := \
- options_unittest.cpp \
- test_main.cpp \
- tests/end_to_end_tests.cpp \
- tests/example_interface_test_data.cpp \
-
-LOCAL_SHARED_LIBRARIES := \
- libchrome-host \
-
-LOCAL_STATIC_LIBRARIES := \
- libaidl-common \
- libgmock_host \
- libgtest_host \
-
-LOCAL_LDLIBS_linux := -lrt
-
-include $(BUILD_HOST_NATIVE_TEST)
-endif # HOST_OS == linux
-
-endif # No TARGET_BUILD_APPS or TARGET_BUILD_PDK
diff --git a/tools/aidl/NOTICE b/tools/aidl/NOTICE
deleted file mode 100644
index c5b1efa7aac7..000000000000
--- a/tools/aidl/NOTICE
+++ /dev/null
@@ -1,190 +0,0 @@
-
- Copyright (c) 2005-2008, The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
-
- 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.
-
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
diff --git a/tools/aidl/Type.cpp b/tools/aidl/Type.cpp
deleted file mode 100644
index d9b8b88bdace..000000000000
--- a/tools/aidl/Type.cpp
+++ /dev/null
@@ -1,1245 +0,0 @@
-#include "Type.h"
-
-#include <sys/types.h>
-
-Namespace NAMES;
-
-Type* VOID_TYPE;
-Type* BOOLEAN_TYPE;
-Type* BYTE_TYPE;
-Type* CHAR_TYPE;
-Type* INT_TYPE;
-Type* LONG_TYPE;
-Type* FLOAT_TYPE;
-Type* DOUBLE_TYPE;
-Type* STRING_TYPE;
-Type* OBJECT_TYPE;
-Type* CHAR_SEQUENCE_TYPE;
-Type* TEXT_UTILS_TYPE;
-Type* REMOTE_EXCEPTION_TYPE;
-Type* RUNTIME_EXCEPTION_TYPE;
-Type* IBINDER_TYPE;
-Type* IINTERFACE_TYPE;
-Type* BINDER_NATIVE_TYPE;
-Type* BINDER_PROXY_TYPE;
-Type* PARCEL_TYPE;
-Type* PARCELABLE_INTERFACE_TYPE;
-Type* CONTEXT_TYPE;
-Type* MAP_TYPE;
-Type* LIST_TYPE;
-Type* CLASSLOADER_TYPE;
-
-Expression* NULL_VALUE;
-Expression* THIS_VALUE;
-Expression* SUPER_VALUE;
-Expression* TRUE_VALUE;
-Expression* FALSE_VALUE;
-
-void
-register_base_types()
-{
- VOID_TYPE = new BasicType("void",
- "XXX", "XXX", "XXX", "XXX", "XXX");
- NAMES.Add(VOID_TYPE);
-
- BOOLEAN_TYPE = new BooleanType();
- NAMES.Add(BOOLEAN_TYPE);
-
- BYTE_TYPE = new BasicType("byte",
- "writeByte", "readByte", "writeByteArray", "createByteArray",
- "readByteArray");
- NAMES.Add(BYTE_TYPE);
-
- CHAR_TYPE = new CharType();
- NAMES.Add(CHAR_TYPE);
-
- INT_TYPE = new BasicType("int",
- "writeInt", "readInt", "writeIntArray", "createIntArray",
- "readIntArray");
- NAMES.Add(INT_TYPE);
-
- LONG_TYPE = new BasicType("long",
- "writeLong", "readLong", "writeLongArray", "createLongArray",
- "readLongArray");
- NAMES.Add(LONG_TYPE);
-
- FLOAT_TYPE = new BasicType("float",
- "writeFloat", "readFloat", "writeFloatArray", "createFloatArray",
- "readFloatArray");
- NAMES.Add(FLOAT_TYPE);
-
- DOUBLE_TYPE = new BasicType("double",
- "writeDouble", "readDouble", "writeDoubleArray",
- "createDoubleArray", "readDoubleArray");
- NAMES.Add(DOUBLE_TYPE);
-
- STRING_TYPE = new StringType();
- NAMES.Add(STRING_TYPE);
-
- OBJECT_TYPE = new Type("java.lang", "Object", Type::BUILT_IN, false, false);
- NAMES.Add(OBJECT_TYPE);
-
- CHAR_SEQUENCE_TYPE = new CharSequenceType();
- NAMES.Add(CHAR_SEQUENCE_TYPE);
-
- MAP_TYPE = new MapType();
- NAMES.Add(MAP_TYPE);
-
- LIST_TYPE = new ListType();
- NAMES.Add(LIST_TYPE);
-
- TEXT_UTILS_TYPE = new Type("android.text", "TextUtils", Type::BUILT_IN, false, false);
- NAMES.Add(TEXT_UTILS_TYPE);
-
- REMOTE_EXCEPTION_TYPE = new RemoteExceptionType();
- NAMES.Add(REMOTE_EXCEPTION_TYPE);
-
- RUNTIME_EXCEPTION_TYPE = new RuntimeExceptionType();
- NAMES.Add(RUNTIME_EXCEPTION_TYPE);
-
- IBINDER_TYPE = new IBinderType();
- NAMES.Add(IBINDER_TYPE);
-
- IINTERFACE_TYPE = new IInterfaceType();
- NAMES.Add(IINTERFACE_TYPE);
-
- BINDER_NATIVE_TYPE = new BinderType();
- NAMES.Add(BINDER_NATIVE_TYPE);
-
- BINDER_PROXY_TYPE = new BinderProxyType();
- NAMES.Add(BINDER_PROXY_TYPE);
-
- PARCEL_TYPE = new ParcelType();
- NAMES.Add(PARCEL_TYPE);
-
- PARCELABLE_INTERFACE_TYPE = new ParcelableInterfaceType();
- NAMES.Add(PARCELABLE_INTERFACE_TYPE);
-
- CONTEXT_TYPE = new Type("android.content", "Context", Type::BUILT_IN, false, false);
- NAMES.Add(CONTEXT_TYPE);
-
- CLASSLOADER_TYPE = new ClassLoaderType();
- NAMES.Add(CLASSLOADER_TYPE);
-
- NULL_VALUE = new LiteralExpression("null");
- THIS_VALUE = new LiteralExpression("this");
- SUPER_VALUE = new LiteralExpression("super");
- TRUE_VALUE = new LiteralExpression("true");
- FALSE_VALUE = new LiteralExpression("false");
-
- NAMES.AddGenericType("java.util", "List", 1);
- NAMES.AddGenericType("java.util", "Map", 2);
-}
-
-static Type*
-make_generic_type(const string& package, const string& name,
- const vector<Type*>& args)
-{
- if (package == "java.util" && name == "List") {
- return new GenericListType("java.util", "List", args);
- }
- return NULL;
- //return new GenericType(package, name, args);
-}
-
-// ================================================================
-
-Type::Type(const string& name, int kind, bool canWriteToParcel, bool canBeOut)
- :m_package(),
- m_name(name),
- m_declFile(""),
- m_declLine(-1),
- m_kind(kind),
- m_canWriteToParcel(canWriteToParcel),
- m_canBeOut(canBeOut)
-{
- m_qualifiedName = name;
-}
-
-Type::Type(const string& package, const string& name,
- int kind, bool canWriteToParcel, bool canBeOut,
- const string& declFile, int declLine)
- :m_package(package),
- m_name(name),
- m_declFile(declFile),
- m_declLine(declLine),
- m_kind(kind),
- m_canWriteToParcel(canWriteToParcel),
- m_canBeOut(canBeOut)
-{
- if (package.length() > 0) {
- m_qualifiedName = package;
- m_qualifiedName += '.';
- }
- m_qualifiedName += name;
-}
-
-Type::~Type()
-{
-}
-
-bool
-Type::CanBeArray() const
-{
- return false;
-}
-
-string
-Type::ImportType() const
-{
- return m_qualifiedName;
-}
-
-string
-Type::CreatorName() const
-{
- return "";
-}
-
-string
-Type::InstantiableName() const
-{
- return QualifiedName();
-}
-
-
-void
-Type::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
- fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%sn",
- __FILE__, __LINE__, m_qualifiedName.c_str());
- addTo->Add(new LiteralExpression("/* WriteToParcel error "
- + m_qualifiedName + " */"));
-}
-
-void
-Type::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
-{
- fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n",
- __FILE__, __LINE__, m_qualifiedName.c_str());
- addTo->Add(new LiteralExpression("/* CreateFromParcel error "
- + m_qualifiedName + " */"));
-}
-
-void
-Type::ReadFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
-{
- fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n",
- __FILE__, __LINE__, m_qualifiedName.c_str());
- addTo->Add(new LiteralExpression("/* ReadFromParcel error "
- + m_qualifiedName + " */"));
-}
-
-void
-Type::WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
- fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n",
- __FILE__, __LINE__, m_qualifiedName.c_str());
- addTo->Add(new LiteralExpression("/* WriteArrayToParcel error "
- + m_qualifiedName + " */"));
-}
-
-void
-Type::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable**)
-{
- fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n",
- __FILE__, __LINE__, m_qualifiedName.c_str());
- addTo->Add(new LiteralExpression("/* CreateArrayFromParcel error "
- + m_qualifiedName + " */"));
-}
-
-void
-Type::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
-{
- fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n",
- __FILE__, __LINE__, m_qualifiedName.c_str());
- addTo->Add(new LiteralExpression("/* ReadArrayFromParcel error "
- + m_qualifiedName + " */"));
-}
-
-void
-Type::SetQualifiedName(const string& qualified)
-{
- m_qualifiedName = qualified;
-}
-
-Expression*
-Type::BuildWriteToParcelFlags(int flags)
-{
- if (flags == 0) {
- return new LiteralExpression("0");
- }
- if ((flags&PARCELABLE_WRITE_RETURN_VALUE) != 0) {
- return new FieldVariable(PARCELABLE_INTERFACE_TYPE,
- "PARCELABLE_WRITE_RETURN_VALUE");
- }
- return new LiteralExpression("0");
-}
-
-// ================================================================
-
-BasicType::BasicType(const string& name, const string& marshallParcel,
- const string& unmarshallParcel, const string& writeArrayParcel,
- const string& createArrayParcel, const string& readArrayParcel)
- :Type(name, BUILT_IN, true, false),
- m_marshallParcel(marshallParcel),
- m_unmarshallParcel(unmarshallParcel),
- m_writeArrayParcel(writeArrayParcel),
- m_createArrayParcel(createArrayParcel),
- m_readArrayParcel(readArrayParcel)
-{
-}
-
-void
-BasicType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
- addTo->Add(new MethodCall(parcel, m_marshallParcel, 1, v));
-}
-
-void
-BasicType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
-{
- addTo->Add(new Assignment(v, new MethodCall(parcel, m_unmarshallParcel)));
-}
-
-bool
-BasicType::CanBeArray() const
-{
- return true;
-}
-
-void
-BasicType::WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
- addTo->Add(new MethodCall(parcel, m_writeArrayParcel, 1, v));
-}
-
-void
-BasicType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable**)
-{
- addTo->Add(new Assignment(v, new MethodCall(parcel, m_createArrayParcel)));
-}
-
-void
-BasicType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
-{
- addTo->Add(new MethodCall(parcel, m_readArrayParcel, 1, v));
-}
-
-// ================================================================
-
-BooleanType::BooleanType()
- :Type("boolean", BUILT_IN, true, false)
-{
-}
-
-void
-BooleanType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
- addTo->Add(new MethodCall(parcel, "writeInt", 1,
- new Ternary(v, new LiteralExpression("1"),
- new LiteralExpression("0"))));
-}
-
-void
-BooleanType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
-{
- addTo->Add(new Assignment(v, new Comparison(new LiteralExpression("0"),
- "!=", new MethodCall(parcel, "readInt"))));
-}
-
-bool
-BooleanType::CanBeArray() const
-{
- return true;
-}
-
-void
-BooleanType::WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
- addTo->Add(new MethodCall(parcel, "writeBooleanArray", 1, v));
-}
-
-void
-BooleanType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable**)
-{
- addTo->Add(new Assignment(v, new MethodCall(parcel, "createBooleanArray")));
-}
-
-void
-BooleanType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
-{
- addTo->Add(new MethodCall(parcel, "readBooleanArray", 1, v));
-}
-
-// ================================================================
-
-CharType::CharType()
- :Type("char", BUILT_IN, true, false)
-{
-}
-
-void
-CharType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
- addTo->Add(new MethodCall(parcel, "writeInt", 1,
- new Cast(INT_TYPE, v)));
-}
-
-void
-CharType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
-{
- addTo->Add(new Assignment(v, new MethodCall(parcel, "readInt"), this));
-}
-
-bool
-CharType::CanBeArray() const
-{
- return true;
-}
-
-void
-CharType::WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
- addTo->Add(new MethodCall(parcel, "writeCharArray", 1, v));
-}
-
-void
-CharType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable**)
-{
- addTo->Add(new Assignment(v, new MethodCall(parcel, "createCharArray")));
-}
-
-void
-CharType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
-{
- addTo->Add(new MethodCall(parcel, "readCharArray", 1, v));
-}
-
-// ================================================================
-
-StringType::StringType()
- :Type("java.lang", "String", BUILT_IN, true, false)
-{
-}
-
-string
-StringType::CreatorName() const
-{
- return "android.os.Parcel.STRING_CREATOR";
-}
-
-void
-StringType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
- addTo->Add(new MethodCall(parcel, "writeString", 1, v));
-}
-
-void
-StringType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
-{
- addTo->Add(new Assignment(v, new MethodCall(parcel, "readString")));
-}
-
-bool
-StringType::CanBeArray() const
-{
- return true;
-}
-
-void
-StringType::WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
- addTo->Add(new MethodCall(parcel, "writeStringArray", 1, v));
-}
-
-void
-StringType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable**)
-{
- addTo->Add(new Assignment(v, new MethodCall(parcel, "createStringArray")));
-}
-
-void
-StringType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
-{
- addTo->Add(new MethodCall(parcel, "readStringArray", 1, v));
-}
-
-// ================================================================
-
-CharSequenceType::CharSequenceType()
- :Type("java.lang", "CharSequence", BUILT_IN, true, false)
-{
-}
-
-string
-CharSequenceType::CreatorName() const
-{
- return "android.os.Parcel.STRING_CREATOR";
-}
-
-void
-CharSequenceType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
- // if (v != null) {
- // parcel.writeInt(1);
- // v.writeToParcel(parcel);
- // } else {
- // parcel.writeInt(0);
- // }
- IfStatement* elsepart = new IfStatement();
- elsepart->statements->Add(new MethodCall(parcel, "writeInt", 1,
- new LiteralExpression("0")));
- IfStatement* ifpart = new IfStatement;
- ifpart->expression = new Comparison(v, "!=", NULL_VALUE);
- ifpart->elseif = elsepart;
- ifpart->statements->Add(new MethodCall(parcel, "writeInt", 1,
- new LiteralExpression("1")));
- ifpart->statements->Add(new MethodCall(TEXT_UTILS_TYPE, "writeToParcel",
- 3, v, parcel, BuildWriteToParcelFlags(flags)));
-
- addTo->Add(ifpart);
-}
-
-void
-CharSequenceType::CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable**)
-{
- // if (0 != parcel.readInt()) {
- // v = TextUtils.createFromParcel(parcel)
- // } else {
- // v = null;
- // }
- IfStatement* elsepart = new IfStatement();
- elsepart->statements->Add(new Assignment(v, NULL_VALUE));
-
- IfStatement* ifpart = new IfStatement();
- ifpart->expression = new Comparison(new LiteralExpression("0"), "!=",
- new MethodCall(parcel, "readInt"));
- ifpart->elseif = elsepart;
- ifpart->statements->Add(new Assignment(v,
- new MethodCall(TEXT_UTILS_TYPE,
- "CHAR_SEQUENCE_CREATOR.createFromParcel", 1, parcel)));
-
- addTo->Add(ifpart);
-}
-
-
-// ================================================================
-
-RemoteExceptionType::RemoteExceptionType()
- :Type("android.os", "RemoteException", BUILT_IN, false, false)
-{
-}
-
-void
-RemoteExceptionType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
- fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
-}
-
-void
-RemoteExceptionType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
-{
- fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
-}
-
-// ================================================================
-
-RuntimeExceptionType::RuntimeExceptionType()
- :Type("java.lang", "RuntimeException", BUILT_IN, false, false)
-{
-}
-
-void
-RuntimeExceptionType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
- fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
-}
-
-void
-RuntimeExceptionType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
-{
- fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
-}
-
-
-// ================================================================
-
-IBinderType::IBinderType()
- :Type("android.os", "IBinder", BUILT_IN, true, false)
-{
-}
-
-void
-IBinderType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
- addTo->Add(new MethodCall(parcel, "writeStrongBinder", 1, v));
-}
-
-void
-IBinderType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
-{
- addTo->Add(new Assignment(v, new MethodCall(parcel, "readStrongBinder")));
-}
-
-void
-IBinderType::WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
- addTo->Add(new MethodCall(parcel, "writeBinderArray", 1, v));
-}
-
-void
-IBinderType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable**)
-{
- addTo->Add(new Assignment(v, new MethodCall(parcel, "createBinderArray")));
-}
-
-void
-IBinderType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
-{
- addTo->Add(new MethodCall(parcel, "readBinderArray", 1, v));
-}
-
-
-// ================================================================
-
-IInterfaceType::IInterfaceType()
- :Type("android.os", "IInterface", BUILT_IN, false, false)
-{
-}
-
-void
-IInterfaceType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
- fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
-}
-
-void
-IInterfaceType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
-{
- fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
-}
-
-
-// ================================================================
-
-BinderType::BinderType()
- :Type("android.os", "Binder", BUILT_IN, false, false)
-{
-}
-
-void
-BinderType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
- fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
-}
-
-void
-BinderType::CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable**)
-{
- fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
-}
-
-
-// ================================================================
-
-BinderProxyType::BinderProxyType()
- :Type("android.os", "BinderProxy", BUILT_IN, false, false)
-{
-}
-
-void
-BinderProxyType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
- fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
-}
-
-void
-BinderProxyType::CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable**)
-{
- fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
-}
-
-
-// ================================================================
-
-ParcelType::ParcelType()
- :Type("android.os", "Parcel", BUILT_IN, false, false)
-{
-}
-
-void
-ParcelType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
- fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
-}
-
-void
-ParcelType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
-{
- fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
-}
-
-// ================================================================
-
-ParcelableInterfaceType::ParcelableInterfaceType()
- :Type("android.os", "Parcelable", BUILT_IN, false, false)
-{
-}
-
-void
-ParcelableInterfaceType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
- fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
-}
-
-void
-ParcelableInterfaceType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
-{
- fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
-}
-
-// ================================================================
-
-MapType::MapType()
- :Type("java.util", "Map", BUILT_IN, true, true)
-{
-}
-
-void
-MapType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
- addTo->Add(new MethodCall(parcel, "writeMap", 1, v));
-}
-
-static void EnsureClassLoader(StatementBlock* addTo, Variable** cl)
-{
- // We don't want to look up the class loader once for every
- // collection argument, so ensure we do it at most once per method.
- if (*cl == NULL) {
- *cl = new Variable(CLASSLOADER_TYPE, "cl");
- addTo->Add(new VariableDeclaration(*cl,
- new LiteralExpression("this.getClass().getClassLoader()"),
- CLASSLOADER_TYPE));
- }
-}
-
-void
-MapType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl)
-{
- EnsureClassLoader(addTo, cl);
- addTo->Add(new Assignment(v, new MethodCall(parcel, "readHashMap", 1, *cl)));
-}
-
-void
-MapType::ReadFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl)
-{
- EnsureClassLoader(addTo, cl);
- addTo->Add(new MethodCall(parcel, "readMap", 2, v, *cl));
-}
-
-
-// ================================================================
-
-ListType::ListType()
- :Type("java.util", "List", BUILT_IN, true, true)
-{
-}
-
-string
-ListType::InstantiableName() const
-{
- return "java.util.ArrayList";
-}
-
-void
-ListType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
- addTo->Add(new MethodCall(parcel, "writeList", 1, v));
-}
-
-void
-ListType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl)
-{
- EnsureClassLoader(addTo, cl);
- addTo->Add(new Assignment(v, new MethodCall(parcel, "readArrayList", 1, *cl)));
-}
-
-void
-ListType::ReadFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl)
-{
- EnsureClassLoader(addTo, cl);
- addTo->Add(new MethodCall(parcel, "readList", 2, v, *cl));
-}
-
-// ================================================================
-
-UserDataType::UserDataType(const string& package, const string& name,
- bool builtIn, bool canWriteToParcel,
- const string& declFile, int declLine)
- :Type(package, name, builtIn ? BUILT_IN : USERDATA, canWriteToParcel,
- true, declFile, declLine)
-{
-}
-
-string
-UserDataType::CreatorName() const
-{
- return QualifiedName() + ".CREATOR";
-}
-
-void
-UserDataType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
- // if (v != null) {
- // parcel.writeInt(1);
- // v.writeToParcel(parcel);
- // } else {
- // parcel.writeInt(0);
- // }
- IfStatement* elsepart = new IfStatement();
- elsepart->statements->Add(new MethodCall(parcel, "writeInt", 1,
- new LiteralExpression("0")));
- IfStatement* ifpart = new IfStatement;
- ifpart->expression = new Comparison(v, "!=", NULL_VALUE);
- ifpart->elseif = elsepart;
- ifpart->statements->Add(new MethodCall(parcel, "writeInt", 1,
- new LiteralExpression("1")));
- ifpart->statements->Add(new MethodCall(v, "writeToParcel", 2,
- parcel, BuildWriteToParcelFlags(flags)));
-
- addTo->Add(ifpart);
-}
-
-void
-UserDataType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
-{
- // if (0 != parcel.readInt()) {
- // v = CLASS.CREATOR.createFromParcel(parcel)
- // } else {
- // v = null;
- // }
- IfStatement* elsepart = new IfStatement();
- elsepart->statements->Add(new Assignment(v, NULL_VALUE));
-
- IfStatement* ifpart = new IfStatement();
- ifpart->expression = new Comparison(new LiteralExpression("0"), "!=",
- new MethodCall(parcel, "readInt"));
- ifpart->elseif = elsepart;
- ifpart->statements->Add(new Assignment(v,
- new MethodCall(v->type, "CREATOR.createFromParcel", 1, parcel)));
-
- addTo->Add(ifpart);
-}
-
-void
-UserDataType::ReadFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable**)
-{
- // TODO: really, we don't need to have this extra check, but we
- // don't have two separate marshalling code paths
- // if (0 != parcel.readInt()) {
- // v.readFromParcel(parcel)
- // }
- IfStatement* ifpart = new IfStatement();
- ifpart->expression = new Comparison(new LiteralExpression("0"), "!=",
- new MethodCall(parcel, "readInt"));
- ifpart->statements->Add(new MethodCall(v, "readFromParcel", 1, parcel));
- addTo->Add(ifpart);
-}
-
-bool
-UserDataType::CanBeArray() const
-{
- return true;
-}
-
-void
-UserDataType::WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
- addTo->Add(new MethodCall(parcel, "writeTypedArray", 2, v,
- BuildWriteToParcelFlags(flags)));
-}
-
-void
-UserDataType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable**)
-{
- string creator = v->type->QualifiedName() + ".CREATOR";
- addTo->Add(new Assignment(v, new MethodCall(parcel,
- "createTypedArray", 1, new LiteralExpression(creator))));
-}
-
-void
-UserDataType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
-{
- string creator = v->type->QualifiedName() + ".CREATOR";
- addTo->Add(new MethodCall(parcel, "readTypedArray", 2,
- v, new LiteralExpression(creator)));
-}
-
-// ================================================================
-
-InterfaceType::InterfaceType(const string& package, const string& name,
- bool builtIn, bool oneway,
- const string& declFile, int declLine)
- :Type(package, name, builtIn ? BUILT_IN : INTERFACE, true, false,
- declFile, declLine)
- ,m_oneway(oneway)
-{
-}
-
-bool
-InterfaceType::OneWay() const
-{
- return m_oneway;
-}
-
-void
-InterfaceType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
- // parcel.writeStrongBinder(v != null ? v.asBinder() : null);
- addTo->Add(new MethodCall(parcel, "writeStrongBinder", 1,
- new Ternary(
- new Comparison(v, "!=", NULL_VALUE),
- new MethodCall(v, "asBinder"),
- NULL_VALUE)));
-}
-
-void
-InterfaceType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
-{
- // v = Interface.asInterface(parcel.readStrongBinder());
- string type = v->type->QualifiedName();
- type += ".Stub";
- addTo->Add(new Assignment(v,
- new MethodCall( NAMES.Find(type), "asInterface", 1,
- new MethodCall(parcel, "readStrongBinder"))));
-}
-
-
-// ================================================================
-
-GenericType::GenericType(const string& package, const string& name,
- const vector<Type*>& args)
- :Type(package, name, BUILT_IN, true, true)
-{
- m_args = args;
-
- m_importName = package + '.' + name;
-
- string gen = "<";
- int N = args.size();
- for (int i=0; i<N; i++) {
- Type* t = args[i];
- gen += t->QualifiedName();
- if (i != N-1) {
- gen += ',';
- }
- }
- gen += '>';
- m_genericArguments = gen;
- SetQualifiedName(m_importName + gen);
-}
-
-const vector<Type*>&
-GenericType::GenericArgumentTypes() const
-{
- return m_args;
-}
-
-string
-GenericType::GenericArguments() const
-{
- return m_genericArguments;
-}
-
-string
-GenericType::ImportType() const
-{
- return m_importName;
-}
-
-void
-GenericType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
- fprintf(stderr, "implement GenericType::WriteToParcel\n");
-}
-
-void
-GenericType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
-{
- fprintf(stderr, "implement GenericType::CreateFromParcel\n");
-}
-
-void
-GenericType::ReadFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable**)
-{
- fprintf(stderr, "implement GenericType::ReadFromParcel\n");
-}
-
-
-// ================================================================
-
-GenericListType::GenericListType(const string& package, const string& name,
- const vector<Type*>& args)
- :GenericType(package, name, args),
- m_creator(args[0]->CreatorName())
-{
-}
-
-string
-GenericListType::CreatorName() const
-{
- return "android.os.Parcel.arrayListCreator";
-}
-
-string
-GenericListType::InstantiableName() const
-{
- return "java.util.ArrayList" + GenericArguments();
-}
-
-void
-GenericListType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
- if (m_creator == STRING_TYPE->CreatorName()) {
- addTo->Add(new MethodCall(parcel, "writeStringList", 1, v));
- } else if (m_creator == IBINDER_TYPE->CreatorName()) {
- addTo->Add(new MethodCall(parcel, "writeBinderList", 1, v));
- } else {
- // parcel.writeTypedListXX(arg);
- addTo->Add(new MethodCall(parcel, "writeTypedList", 1, v));
- }
-}
-
-void
-GenericListType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
-{
- if (m_creator == STRING_TYPE->CreatorName()) {
- addTo->Add(new Assignment(v,
- new MethodCall(parcel, "createStringArrayList", 0)));
- } else if (m_creator == IBINDER_TYPE->CreatorName()) {
- addTo->Add(new Assignment(v,
- new MethodCall(parcel, "createBinderArrayList", 0)));
- } else {
- // v = _data.readTypedArrayList(XXX.creator);
- addTo->Add(new Assignment(v,
- new MethodCall(parcel, "createTypedArrayList", 1,
- new LiteralExpression(m_creator))));
- }
-}
-
-void
-GenericListType::ReadFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable**)
-{
- if (m_creator == STRING_TYPE->CreatorName()) {
- addTo->Add(new MethodCall(parcel, "readStringList", 1, v));
- } else if (m_creator == IBINDER_TYPE->CreatorName()) {
- addTo->Add(new MethodCall(parcel, "readBinderList", 1, v));
- } else {
- // v = _data.readTypedList(v, XXX.creator);
- addTo->Add(new MethodCall(parcel, "readTypedList", 2,
- v,
- new LiteralExpression(m_creator)));
- }
-}
-
-
-// ================================================================
-
-ClassLoaderType::ClassLoaderType()
- :Type("java.lang", "ClassLoader", BUILT_IN, false, false)
-{
-}
-
-
-// ================================================================
-
-Namespace::Namespace()
-{
-}
-
-Namespace::~Namespace()
-{
- int N = m_types.size();
- for (int i=0; i<N; i++) {
- delete m_types[i];
- }
-}
-
-void
-Namespace::Add(Type* type)
-{
- Type* t = Find(type->QualifiedName());
- if (t == NULL) {
- m_types.push_back(type);
- }
-}
-
-void
-Namespace::AddGenericType(const string& package, const string& name, int args)
-{
- Generic g;
- g.package = package;
- g.name = name;
- g.qualified = package + '.' + name;
- g.args = args;
- m_generics.push_back(g);
-}
-
-Type*
-Namespace::Find(const string& name) const
-{
- int N = m_types.size();
- for (int i=0; i<N; i++) {
- if (m_types[i]->QualifiedName() == name) {
- return m_types[i];
- }
- }
- return NULL;
-}
-
-Type*
-Namespace::Find(const char* package, const char* name) const
-{
- string s;
- if (package != NULL) {
- s += package;
- s += '.';
- }
- s += name;
- return Find(s);
-}
-
-static string
-normalize_generic(const string& s)
-{
- string r;
- int N = s.size();
- for (int i=0; i<N; i++) {
- char c = s[i];
- if (!isspace(c)) {
- r += c;
- }
- }
- return r;
-}
-
-Type*
-Namespace::Search(const string& name)
-{
- // an exact match wins
- Type* result = Find(name);
- if (result != NULL) {
- return result;
- }
-
- // try the class names
- // our language doesn't allow you to not specify outer classes
- // when referencing an inner class. that could be changed, and this
- // would be the place to do it, but I don't think the complexity in
- // scoping rules is worth it.
- int N = m_types.size();
- for (int i=0; i<N; i++) {
- if (m_types[i]->Name() == name) {
- return m_types[i];
- }
- }
-
- // we got to here and it's not a generic, give up
- if (name.find('<') == name.npos) {
- return NULL;
- }
-
- // remove any whitespace
- string normalized = normalize_generic(name);
-
- // find the part before the '<', find a generic for it
- ssize_t baseIndex = normalized.find('<');
- string base(normalized.c_str(), baseIndex);
- const Generic* g = search_generic(base);
- if (g == NULL) {
- return NULL;
- }
-
- // For each of the args, do a recursive search on it. We don't allow
- // generics within generics like Java does, because we're really limiting
- // them to just built-in container classes, at least for now. Our syntax
- // ensures this right now as well.
- vector<Type*> args;
- size_t start = baseIndex + 1;
- size_t end = start;
- while (normalized[start] != '\0') {
- end = normalized.find(',', start);
- if (end == normalized.npos) {
- end = normalized.find('>', start);
- }
- string s(normalized.c_str()+start, end-start);
- Type* t = this->Search(s);
- if (t == NULL) {
- // maybe we should print a warning here?
- return NULL;
- }
- args.push_back(t);
- start = end+1;
- }
-
- // construct a GenericType, add it to our name set so they always get
- // the same object, and return it.
- result = make_generic_type(g->package, g->name, args);
- if (result == NULL) {
- return NULL;
- }
-
- this->Add(result);
- return this->Find(result->QualifiedName());
-}
-
-const Namespace::Generic*
-Namespace::search_generic(const string& name) const
-{
- int N = m_generics.size();
-
- // first exact match
- for (int i=0; i<N; i++) {
- const Generic& g = m_generics[i];
- if (g.qualified == name) {
- return &g;
- }
- }
-
- // then name match
- for (int i=0; i<N; i++) {
- const Generic& g = m_generics[i];
- if (g.name == name) {
- return &g;
- }
- }
-
- return NULL;
-}
-
-void
-Namespace::Dump() const
-{
- int n = m_types.size();
- for (int i=0; i<n; i++) {
- Type* t = m_types[i];
- printf("type: package=%s name=%s qualifiedName=%s\n",
- t->Package().c_str(), t->Name().c_str(),
- t->QualifiedName().c_str());
- }
-}
diff --git a/tools/aidl/Type.h b/tools/aidl/Type.h
deleted file mode 100644
index 6ede79adeaf9..000000000000
--- a/tools/aidl/Type.h
+++ /dev/null
@@ -1,472 +0,0 @@
-#ifndef AIDL_TYPE_H_
-#define AIDL_TYPE_H_
-
-#include "AST.h"
-#include <string>
-#include <vector>
-
-using namespace std;
-
-class Type
-{
-public:
- // kinds
- enum {
- BUILT_IN,
- USERDATA,
- INTERFACE,
- GENERATED
- };
-
- // WriteToParcel flags
- enum {
- PARCELABLE_WRITE_RETURN_VALUE = 0x0001
- };
-
- Type(const string& name, int kind, bool canWriteToParcel,
- bool canBeOut);
- Type(const string& package, const string& name,
- int kind, bool canWriteToParcel, bool canBeOut,
- const string& declFile = "", int declLine = -1);
- virtual ~Type();
-
- inline string Package() const { return m_package; }
- inline string Name() const { return m_name; }
- inline string QualifiedName() const { return m_qualifiedName; }
- inline int Kind() const { return m_kind; }
- inline string DeclFile() const { return m_declFile; }
- inline int DeclLine() const { return m_declLine; }
- inline bool CanWriteToParcel() const { return m_canWriteToParcel; }
- inline bool CanBeOutParameter() const { return m_canBeOut; }
-
- virtual string ImportType() const;
- virtual string CreatorName() const;
- virtual string InstantiableName() const;
-
- virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, int flags);
- virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl);
- virtual void ReadFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl);
-
- virtual bool CanBeArray() const;
-
- virtual void WriteArrayToParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, int flags);
- virtual void CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl);
- virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl);
-
-protected:
- void SetQualifiedName(const string& qualified);
- Expression* BuildWriteToParcelFlags(int flags);
-
-private:
- Type();
- Type(const Type&);
-
- string m_package;
- string m_name;
- string m_qualifiedName;
- string m_declFile;
- int m_declLine;
- int m_kind;
- bool m_canWriteToParcel;
- bool m_canBeOut;
-};
-
-class BasicType : public Type
-{
-public:
- BasicType(const string& name,
- const string& marshallParcel,
- const string& unmarshallParcel,
- const string& writeArrayParcel,
- const string& createArrayParcel,
- const string& readArrayParcel);
-
- virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, int flags);
- virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl);
-
- virtual bool CanBeArray() const;
-
- virtual void WriteArrayToParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, int flags);
- virtual void CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl);
- virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl);
-
-private:
- string m_marshallParcel;
- string m_unmarshallParcel;
- string m_writeArrayParcel;
- string m_createArrayParcel;
- string m_readArrayParcel;
-};
-
-class BooleanType : public Type
-{
-public:
- BooleanType();
-
- virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, int flags);
- virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl);
-
- virtual bool CanBeArray() const;
-
- virtual void WriteArrayToParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, int flags);
- virtual void CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl);
- virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl);
-};
-
-class CharType : public Type
-{
-public:
- CharType();
-
- virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, int flags);
- virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl);
-
- virtual bool CanBeArray() const;
-
- virtual void WriteArrayToParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, int flags);
- virtual void CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl);
- virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl);
-};
-
-
-class StringType : public Type
-{
-public:
- StringType();
-
- virtual string CreatorName() const;
-
- virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, int flags);
- virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl);
-
- virtual bool CanBeArray() const;
-
- virtual void WriteArrayToParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, int flags);
- virtual void CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl);
- virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl);
-};
-
-class CharSequenceType : public Type
-{
-public:
- CharSequenceType();
-
- virtual string CreatorName() const;
-
- virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, int flags);
- virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl);
-};
-
-class RemoteExceptionType : public Type
-{
-public:
- RemoteExceptionType();
-
- virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, int flags);
- virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl);
-};
-
-class RuntimeExceptionType : public Type
-{
-public:
- RuntimeExceptionType();
-
- virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, int flags);
- virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl);
-};
-
-class IBinderType : public Type
-{
-public:
- IBinderType();
-
- virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, int flags);
- virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl);
-
- virtual void WriteArrayToParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, int flags);
- virtual void CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl);
- virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl);
-};
-
-class IInterfaceType : public Type
-{
-public:
- IInterfaceType();
-
- virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, int flags);
- virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl);
-};
-
-class BinderType : public Type
-{
-public:
- BinderType();
-
- virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, int flags);
- virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl);
-};
-
-class BinderProxyType : public Type
-{
-public:
- BinderProxyType();
-
- virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, int flags);
- virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl);
-};
-
-class ParcelType : public Type
-{
-public:
- ParcelType();
-
- virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, int flags);
- virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl);
-};
-
-class ParcelableInterfaceType : public Type
-{
-public:
- ParcelableInterfaceType();
-
- virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, int flags);
- virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl);
-};
-
-class MapType : public Type
-{
-public:
- MapType();
-
- virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, int flags);
- virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl);
- virtual void ReadFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl);
-};
-
-class ListType : public Type
-{
-public:
- ListType();
-
- virtual string InstantiableName() const;
-
- virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, int flags);
- virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl);
- virtual void ReadFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl);
-};
-
-class UserDataType : public Type
-{
-public:
- UserDataType(const string& package, const string& name,
- bool builtIn, bool canWriteToParcel,
- const string& declFile = "", int declLine = -1);
-
- virtual string CreatorName() const;
-
- virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, int flags);
- virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl);
- virtual void ReadFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl);
-
- virtual bool CanBeArray() const;
-
- virtual void WriteArrayToParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, int flags);
- virtual void CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl);
- virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl);
-};
-
-class InterfaceType : public Type
-{
-public:
- InterfaceType(const string& package, const string& name,
- bool builtIn, bool oneway,
- const string& declFile, int declLine);
-
- bool OneWay() const;
-
- virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, int flags);
- virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl);
-
-private:
- bool m_oneway;
-};
-
-
-class GenericType : public Type
-{
-public:
- GenericType(const string& package, const string& name,
- const vector<Type*>& args);
-
- const vector<Type*>& GenericArgumentTypes() const;
- string GenericArguments() const;
-
- virtual string ImportType() const;
-
- virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, int flags);
- virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl);
- virtual void ReadFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl);
-
-private:
- string m_genericArguments;
- string m_importName;
- vector<Type*> m_args;
-};
-
-class ClassLoaderType : public Type
-{
-public:
- ClassLoaderType();
-};
-
-class GenericListType : public GenericType
-{
-public:
- GenericListType(const string& package, const string& name,
- const vector<Type*>& args);
-
- virtual string CreatorName() const;
- virtual string InstantiableName() const;
-
- virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, int flags);
- virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl);
- virtual void ReadFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl);
-
-private:
- string m_creator;
-};
-
-class Namespace
-{
-public:
- Namespace();
- ~Namespace();
- void Add(Type* type);
-
- // args is the number of template types (what is this called?)
- void AddGenericType(const string& package, const string& name, int args);
-
- // lookup a specific class name
- Type* Find(const string& name) const;
- Type* Find(const char* package, const char* name) const;
-
- // try to search by either a full name or a partial name
- Type* Search(const string& name);
-
- void Dump() const;
-
-private:
- struct Generic {
- string package;
- string name;
- string qualified;
- int args;
- };
-
- const Generic* search_generic(const string& name) const;
-
- vector<Type*> m_types;
- vector<Generic> m_generics;
-};
-
-extern Namespace NAMES;
-
-extern Type* VOID_TYPE;
-extern Type* BOOLEAN_TYPE;
-extern Type* BYTE_TYPE;
-extern Type* CHAR_TYPE;
-extern Type* INT_TYPE;
-extern Type* LONG_TYPE;
-extern Type* FLOAT_TYPE;
-extern Type* DOUBLE_TYPE;
-extern Type* OBJECT_TYPE;
-extern Type* STRING_TYPE;
-extern Type* CHAR_SEQUENCE_TYPE;
-extern Type* TEXT_UTILS_TYPE;
-extern Type* REMOTE_EXCEPTION_TYPE;
-extern Type* RUNTIME_EXCEPTION_TYPE;
-extern Type* IBINDER_TYPE;
-extern Type* IINTERFACE_TYPE;
-extern Type* BINDER_NATIVE_TYPE;
-extern Type* BINDER_PROXY_TYPE;
-extern Type* PARCEL_TYPE;
-extern Type* PARCELABLE_INTERFACE_TYPE;
-
-extern Type* CONTEXT_TYPE;
-
-extern Expression* NULL_VALUE;
-extern Expression* THIS_VALUE;
-extern Expression* SUPER_VALUE;
-extern Expression* TRUE_VALUE;
-extern Expression* FALSE_VALUE;
-
-void register_base_types();
-
-#endif // AIDL_TYPE_H_
diff --git a/tools/aidl/aidl.cpp b/tools/aidl/aidl.cpp
deleted file mode 100644
index 616f2768cd7b..000000000000
--- a/tools/aidl/aidl.cpp
+++ /dev/null
@@ -1,1072 +0,0 @@
-
-#include "aidl_language.h"
-#include "options.h"
-#include "os.h"
-#include "search_path.h"
-#include "Type.h"
-#include "generate_java.h"
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/param.h>
-#include <sys/stat.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <map>
-
-#ifdef _WIN32
-#include <io.h>
-#include <direct.h>
-#include <sys/stat.h>
-#endif
-
-#ifndef O_BINARY
-# define O_BINARY 0
-#endif
-
-// The following are gotten as the offset from the allowable id's between
-// android.os.IBinder.FIRST_CALL_TRANSACTION=1 and
-// android.os.IBinder.LAST_CALL_TRANSACTION=16777215
-#define MIN_USER_SET_METHOD_ID 0
-#define MAX_USER_SET_METHOD_ID 16777214
-
-using namespace std;
-
-ParseState *psGlobal;
-
-static void
-test_document(document_item_type* d)
-{
- while (d) {
- if (d->item_type == INTERFACE_TYPE_BINDER) {
- interface_type* c = (interface_type*)d;
- printf("interface %s %s {\n", c->package, c->name.data);
- interface_item_type *q = (interface_item_type*)c->interface_items;
- while (q) {
- if (q->item_type == METHOD_TYPE) {
- method_type *m = (method_type*)q;
- printf(" %s %s(", m->type.type.data, m->name.data);
- arg_type *p = m->args;
- while (p) {
- printf("%s %s",p->type.type.data,p->name.data);
- if (p->next) printf(", ");
- p=p->next;
- }
- printf(")");
- printf(";\n");
- }
- q=q->next;
- }
- printf("}\n");
- }
- else if (d->item_type == USER_DATA_TYPE) {
- user_data_type* b = (user_data_type*)d;
- if (b->parcelable) {
- printf("parcelable %s %s;\n", b->package, b->name.data);
- }
- }
- else {
- printf("UNKNOWN d=0x%08lx d->item_type=%d\n", (long)d, d->item_type);
- }
- d = d->next;
- }
-}
-
-// ==========================================================
-int
-convert_direction(const char* direction)
-{
- if (direction == NULL) {
- return IN_PARAMETER;
- }
- if (0 == strcmp(direction, "in")) {
- return IN_PARAMETER;
- }
- if (0 == strcmp(direction, "out")) {
- return OUT_PARAMETER;
- }
- return INOUT_PARAMETER;
-}
-
-// ==========================================================
-struct import_info {
- const char* from;
- const char* filename;
- buffer_type statement;
- const char* neededClass;
- document_item_type* doc;
- struct import_info* next;
-};
-
-document_item_type* g_document = NULL;
-import_info* g_imports = NULL;
-
-static void
-main_document_parsed(document_item_type* d)
-{
- g_document = d;
-}
-
-static void
-main_import_parsed(buffer_type* statement)
-{
- import_info* import = (import_info*)malloc(sizeof(import_info));
- memset(import, 0, sizeof(import_info));
- import->from = strdup(psGlobal->FileName().c_str());
- import->statement.lineno = statement->lineno;
- import->statement.data = strdup(statement->data);
- import->statement.extra = NULL;
- import->next = g_imports;
- import->neededClass = parse_import_statement(statement->data);
- g_imports = import;
-}
-
-static ParserCallbacks g_mainCallbacks = {
- &main_document_parsed,
- &main_import_parsed
-};
-
-char*
-parse_import_statement(const char* text)
-{
- const char* end;
- int len;
-
- while (isspace(*text)) {
- text++;
- }
- while (!isspace(*text)) {
- text++;
- }
- while (isspace(*text)) {
- text++;
- }
- end = text;
- while (!isspace(*end) && *end != ';') {
- end++;
- }
- len = end-text;
-
- char* rv = (char*)malloc(len+1);
- memcpy(rv, text, len);
- rv[len] = '\0';
-
- return rv;
-}
-
-// ==========================================================
-static void
-import_import_parsed(buffer_type* statement)
-{
-}
-
-// ==========================================================
-static int
-check_filename(const char* filename, const char* package, buffer_type* name)
-{
- const char* p;
- string expected;
- string fn;
- size_t len;
- char cwd[MAXPATHLEN];
- bool valid = false;
-
-#ifdef _WIN32
- if (isalpha(filename[0]) && filename[1] == ':'
- && filename[2] == OS_PATH_SEPARATOR) {
-#else
- if (filename[0] == OS_PATH_SEPARATOR) {
-#endif
- fn = filename;
- } else {
- fn = getcwd(cwd, sizeof(cwd));
- len = fn.length();
- if (fn[len-1] != OS_PATH_SEPARATOR) {
- fn += OS_PATH_SEPARATOR;
- }
- fn += filename;
- }
-
- if (package) {
- expected = package;
- expected += '.';
- }
-
- len = expected.length();
- for (size_t i=0; i<len; i++) {
- if (expected[i] == '.') {
- expected[i] = OS_PATH_SEPARATOR;
- }
- }
-
- p = strchr(name->data, '.');
- len = p ? p-name->data : strlen(name->data);
- expected.append(name->data, len);
-
- expected += ".aidl";
-
- len = fn.length();
- valid = (len >= expected.length());
-
- if (valid) {
- p = fn.c_str() + (len - expected.length());
-
-#ifdef _WIN32
- if (OS_PATH_SEPARATOR != '/') {
- // Input filename under cygwin most likely has / separators
- // whereas the expected string uses \\ separators. Adjust
- // them accordingly.
- for (char *c = const_cast<char *>(p); *c; ++c) {
- if (*c == '/') *c = OS_PATH_SEPARATOR;
- }
- }
-#endif
-
- // aidl assumes case-insensitivity on Mac Os and Windows.
-#if defined(__linux__)
- valid = (expected == p);
-#else
- valid = !strcasecmp(expected.c_str(), p);
-#endif
- }
-
- if (!valid) {
- fprintf(stderr, "%s:%d interface %s should be declared in a file"
- " called %s.\n",
- filename, name->lineno, name->data, expected.c_str());
- return 1;
- }
-
- return 0;
-}
-
-static int
-check_filenames(const char* filename, document_item_type* items)
-{
- int err = 0;
- while (items) {
- if (items->item_type == USER_DATA_TYPE) {
- user_data_type* p = (user_data_type*)items;
- err |= check_filename(filename, p->package, &p->name);
- }
- else if (items->item_type == INTERFACE_TYPE_BINDER) {
- interface_type* c = (interface_type*)items;
- err |= check_filename(filename, c->package, &c->name);
- }
- else {
- fprintf(stderr, "aidl: internal error unkown document type %d.\n",
- items->item_type);
- return 1;
- }
- items = items->next;
- }
- return err;
-}
-
-// ==========================================================
-static const char*
-kind_to_string(int kind)
-{
- switch (kind)
- {
- case Type::INTERFACE:
- return "an interface";
- case Type::USERDATA:
- return "a user data";
- default:
- return "ERROR";
- }
-}
-
-static char*
-rfind(char* str, char c)
-{
- char* p = str + strlen(str) - 1;
- while (p >= str) {
- if (*p == c) {
- return p;
- }
- p--;
- }
- return NULL;
-}
-
-static int
-gather_types(const char* filename, document_item_type* items)
-{
- int err = 0;
- while (items) {
- Type* type;
- if (items->item_type == USER_DATA_TYPE) {
- user_data_type* p = (user_data_type*)items;
- type = new UserDataType(p->package ? p->package : "", p->name.data,
- false, p->parcelable, filename, p->name.lineno);
- }
- else if (items->item_type == INTERFACE_TYPE_BINDER) {
- interface_type* c = (interface_type*)items;
- type = new InterfaceType(c->package ? c->package : "",
- c->name.data, false, c->oneway,
- filename, c->name.lineno);
- }
- else {
- fprintf(stderr, "aidl: internal error %s:%d\n", __FILE__, __LINE__);
- return 1;
- }
-
- Type* old = NAMES.Find(type->QualifiedName());
- if (old == NULL) {
- NAMES.Add(type);
-
- if (items->item_type == INTERFACE_TYPE_BINDER) {
- // for interfaces, also add the stub and proxy types, we don't
- // bother checking these for duplicates, because the parser
- // won't let us do it.
- interface_type* c = (interface_type*)items;
-
- string name = c->name.data;
- name += ".Stub";
- Type* stub = new Type(c->package ? c->package : "",
- name, Type::GENERATED, false, false,
- filename, c->name.lineno);
- NAMES.Add(stub);
-
- name = c->name.data;
- name += ".Stub.Proxy";
- Type* proxy = new Type(c->package ? c->package : "",
- name, Type::GENERATED, false, false,
- filename, c->name.lineno);
- NAMES.Add(proxy);
- }
- } else {
- if (old->Kind() == Type::BUILT_IN) {
- fprintf(stderr, "%s:%d attempt to redefine built in class %s\n",
- filename, type->DeclLine(),
- type->QualifiedName().c_str());
- err = 1;
- }
- else if (type->Kind() != old->Kind()) {
- const char* oldKind = kind_to_string(old->Kind());
- const char* newKind = kind_to_string(type->Kind());
-
- fprintf(stderr, "%s:%d attempt to redefine %s as %s,\n",
- filename, type->DeclLine(),
- type->QualifiedName().c_str(), newKind);
- fprintf(stderr, "%s:%d previously defined here as %s.\n",
- old->DeclFile().c_str(), old->DeclLine(), oldKind);
- err = 1;
- }
- }
-
- items = items->next;
- }
- return err;
-}
-
-// ==========================================================
-static bool
-matches_keyword(const char* str)
-{
- static const char* KEYWORDS[] = { "abstract", "assert", "boolean", "break",
- "byte", "case", "catch", "char", "class", "const", "continue",
- "default", "do", "double", "else", "enum", "extends", "final",
- "finally", "float", "for", "goto", "if", "implements", "import",
- "instanceof", "int", "interface", "long", "native", "new", "package",
- "private", "protected", "public", "return", "short", "static",
- "strictfp", "super", "switch", "synchronized", "this", "throw",
- "throws", "transient", "try", "void", "volatile", "while",
- "true", "false", "null",
- NULL
- };
- const char** k = KEYWORDS;
- while (*k) {
- if (0 == strcmp(str, *k)) {
- return true;
- }
- k++;
- }
- return false;
-}
-
-static int
-check_method(const char* filename, method_type* m)
-{
- int err = 0;
-
- // return type
- Type* returnType = NAMES.Search(m->type.type.data);
- if (returnType == NULL) {
- fprintf(stderr, "%s:%d unknown return type %s\n", filename,
- m->type.type.lineno, m->type.type.data);
- err = 1;
- return err;
- }
-
- if (!returnType->CanWriteToParcel()) {
- fprintf(stderr, "%s:%d return type %s can't be marshalled.\n", filename,
- m->type.type.lineno, m->type.type.data);
- err = 1;
- }
-
- if (m->type.dimension > 0 && !returnType->CanBeArray()) {
- fprintf(stderr, "%s:%d return type %s%s can't be an array.\n", filename,
- m->type.array_token.lineno, m->type.type.data,
- m->type.array_token.data);
- err = 1;
- }
-
- if (m->type.dimension > 1) {
- fprintf(stderr, "%s:%d return type %s%s only one"
- " dimensional arrays are supported\n", filename,
- m->type.array_token.lineno, m->type.type.data,
- m->type.array_token.data);
- err = 1;
- }
-
- int index = 1;
-
- arg_type* arg = m->args;
- while (arg) {
- Type* t = NAMES.Search(arg->type.type.data);
-
- // check the arg type
- if (t == NULL) {
- fprintf(stderr, "%s:%d parameter %s (%d) unknown type %s\n",
- filename, m->type.type.lineno, arg->name.data, index,
- arg->type.type.data);
- err = 1;
- goto next;
- }
-
- if (!t->CanWriteToParcel()) {
- fprintf(stderr, "%s:%d parameter %d: '%s %s' can't be marshalled.\n",
- filename, m->type.type.lineno, index,
- arg->type.type.data, arg->name.data);
- err = 1;
- }
-
- if (arg->direction.data == NULL
- && (arg->type.dimension != 0 || t->CanBeOutParameter())) {
- fprintf(stderr, "%s:%d parameter %d: '%s %s' can be an out"
- " parameter, so you must declare it as in,"
- " out or inout.\n",
- filename, m->type.type.lineno, index,
- arg->type.type.data, arg->name.data);
- err = 1;
- }
-
- if (convert_direction(arg->direction.data) != IN_PARAMETER
- && !t->CanBeOutParameter()
- && arg->type.dimension == 0) {
- fprintf(stderr, "%s:%d parameter %d: '%s %s %s' can only be an in"
- " parameter.\n",
- filename, m->type.type.lineno, index,
- arg->direction.data, arg->type.type.data,
- arg->name.data);
- err = 1;
- }
-
- if (arg->type.dimension > 0 && !t->CanBeArray()) {
- fprintf(stderr, "%s:%d parameter %d: '%s %s%s %s' can't be an"
- " array.\n", filename,
- m->type.array_token.lineno, index, arg->direction.data,
- arg->type.type.data, arg->type.array_token.data,
- arg->name.data);
- err = 1;
- }
-
- if (arg->type.dimension > 1) {
- fprintf(stderr, "%s:%d parameter %d: '%s %s%s %s' only one"
- " dimensional arrays are supported\n", filename,
- m->type.array_token.lineno, index, arg->direction.data,
- arg->type.type.data, arg->type.array_token.data,
- arg->name.data);
- err = 1;
- }
-
- // check that the name doesn't match a keyword
- if (matches_keyword(arg->name.data)) {
- fprintf(stderr, "%s:%d parameter %d %s is named the same as a"
- " Java or aidl keyword\n",
- filename, m->name.lineno, index, arg->name.data);
- err = 1;
- }
-
-next:
- index++;
- arg = arg->next;
- }
-
- return err;
-}
-
-static int
-check_types(const char* filename, document_item_type* items)
-{
- int err = 0;
- while (items) {
- // (nothing to check for USER_DATA_TYPE)
- if (items->item_type == INTERFACE_TYPE_BINDER) {
- map<string,method_type*> methodNames;
- interface_type* c = (interface_type*)items;
-
- interface_item_type* member = c->interface_items;
- while (member) {
- if (member->item_type == METHOD_TYPE) {
- method_type* m = (method_type*)member;
-
- err |= check_method(filename, m);
-
- // prevent duplicate methods
- if (methodNames.find(m->name.data) == methodNames.end()) {
- methodNames[m->name.data] = m;
- } else {
- fprintf(stderr,"%s:%d attempt to redefine method %s,\n",
- filename, m->name.lineno, m->name.data);
- method_type* old = methodNames[m->name.data];
- fprintf(stderr, "%s:%d previously defined here.\n",
- filename, old->name.lineno);
- err = 1;
- }
- }
- member = member->next;
- }
- }
-
- items = items->next;
- }
- return err;
-}
-
-// ==========================================================
-static int
-exactly_one_interface(const char* filename, const document_item_type* items, const Options& options,
- bool* onlyParcelable)
-{
- if (items == NULL) {
- fprintf(stderr, "%s: file does not contain any interfaces\n",
- filename);
- return 1;
- }
-
- const document_item_type* next = items->next;
- // Allow parcelables to skip the "one-only" rule.
- if (items->next != NULL && next->item_type != USER_DATA_TYPE) {
- int lineno = -1;
- if (next->item_type == INTERFACE_TYPE_BINDER) {
- lineno = ((interface_type*)next)->interface_token.lineno;
- }
- fprintf(stderr, "%s:%d aidl can only handle one interface per file\n",
- filename, lineno);
- return 1;
- }
-
- if (items->item_type == USER_DATA_TYPE) {
- *onlyParcelable = true;
- if (options.failOnParcelable) {
- fprintf(stderr, "%s:%d aidl can only generate code for interfaces, not"
- " parcelables,\n", filename,
- ((user_data_type*)items)->keyword_token.lineno);
- fprintf(stderr, "%s:%d .aidl files that only declare parcelables"
- "may not go in the Makefile.\n", filename,
- ((user_data_type*)items)->keyword_token.lineno);
- return 1;
- }
- } else {
- *onlyParcelable = false;
- }
-
- return 0;
-}
-
-// ==========================================================
-void
-generate_dep_file(const Options& options, const document_item_type* items)
-{
- /* we open the file in binary mode to ensure that the same output is
- * generated on all platforms !!
- */
- FILE* to = NULL;
- if (options.autoDepFile) {
- string fileName = options.outputFileName + ".d";
- to = fopen(fileName.c_str(), "wb");
- } else {
- to = fopen(options.depFileName.c_str(), "wb");
- }
-
- if (to == NULL) {
- return;
- }
-
- const char* slash = "\\";
- import_info* import = g_imports;
- if (import == NULL) {
- slash = "";
- }
-
- if (items->item_type == INTERFACE_TYPE_BINDER) {
- fprintf(to, "%s: \\\n", options.outputFileName.c_str());
- } else {
- // parcelable: there's no output file.
- fprintf(to, " : \\\n");
- }
- fprintf(to, " %s %s\n", options.inputFileName.c_str(), slash);
-
- while (import) {
- if (import->next == NULL) {
- slash = "";
- }
- if (import->filename) {
- fprintf(to, " %s %s\n", import->filename, slash);
- }
- import = import->next;
- }
-
- fprintf(to, "\n");
-
- // Output "<input_aidl_file>: " so make won't fail if the input .aidl file
- // has been deleted, moved or renamed in incremental build.
- fprintf(to, "%s :\n", options.inputFileName.c_str());
-
- // Output "<imported_file>: " so make won't fail if the imported file has
- // been deleted, moved or renamed in incremental build.
- import = g_imports;
- while (import) {
- if (import->filename) {
- fprintf(to, "%s :\n", import->filename);
- }
- import = import->next;
- }
-
- fclose(to);
-}
-
-// ==========================================================
-static string
-generate_outputFileName2(const Options& options, const buffer_type& name, const char* package)
-{
- string result;
-
- // create the path to the destination folder based on the
- // interface package name
- result = options.outputBaseFolder;
- result += OS_PATH_SEPARATOR;
-
- string packageStr = package;
- size_t len = packageStr.length();
- for (size_t i=0; i<len; i++) {
- if (packageStr[i] == '.') {
- packageStr[i] = OS_PATH_SEPARATOR;
- }
- }
-
- result += packageStr;
-
- // add the filename by replacing the .aidl extension to .java
- const char* p = strchr(name.data, '.');
- len = p ? p-name.data : strlen(name.data);
-
- result += OS_PATH_SEPARATOR;
- result.append(name.data, len);
- result += ".java";
-
- return result;
-}
-
-// ==========================================================
-static string
-generate_outputFileName(const Options& options, const document_item_type* items)
-{
- // items has already been checked to have only one interface.
- if (items->item_type == INTERFACE_TYPE_BINDER) {
- interface_type* type = (interface_type*)items;
-
- return generate_outputFileName2(options, type->name, type->package);
- } else if (items->item_type == USER_DATA_TYPE) {
- user_data_type* type = (user_data_type*)items;
- return generate_outputFileName2(options, type->name, type->package);
- }
-
- // I don't think we can come here, but safer than returning NULL.
- string result;
- return result;
-}
-
-
-
-// ==========================================================
-static void
-check_outputFilePath(const string& path) {
- size_t len = path.length();
- for (size_t i=0; i<len ; i++) {
- if (path[i] == OS_PATH_SEPARATOR) {
- string p = path.substr(0, i);
- if (access(path.data(), F_OK) != 0) {
-#ifdef _WIN32
- _mkdir(p.data());
-#else
- mkdir(p.data(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP);
-#endif
- }
- }
- }
-}
-
-
-// ==========================================================
-static int
-parse_preprocessed_file(const string& filename)
-{
- int err;
-
- FILE* f = fopen(filename.c_str(), "rb");
- if (f == NULL) {
- fprintf(stderr, "aidl: can't open preprocessed file: %s\n",
- filename.c_str());
- return 1;
- }
-
- int lineno = 1;
- char line[1024];
- char type[1024];
- char fullname[1024];
- while (fgets(line, sizeof(line), f)) {
- // skip comments and empty lines
- if (!line[0] || strncmp(line, "//", 2) == 0) {
- continue;
- }
-
- sscanf(line, "%s %[^; \r\n\t];", type, fullname);
-
- char* packagename;
- char* classname = rfind(fullname, '.');
- if (classname != NULL) {
- *classname = '\0';
- classname++;
- packagename = fullname;
- } else {
- classname = fullname;
- packagename = NULL;
- }
-
- //printf("%s:%d:...%s...%s...%s...\n", filename.c_str(), lineno,
- // type, packagename, classname);
- document_item_type* doc;
-
- if (0 == strcmp("parcelable", type)) {
- user_data_type* parcl = (user_data_type*)malloc(
- sizeof(user_data_type));
- memset(parcl, 0, sizeof(user_data_type));
- parcl->document_item.item_type = USER_DATA_TYPE;
- parcl->keyword_token.lineno = lineno;
- parcl->keyword_token.data = strdup(type);
- parcl->package = packagename ? strdup(packagename) : NULL;
- parcl->name.lineno = lineno;
- parcl->name.data = strdup(classname);
- parcl->semicolon_token.lineno = lineno;
- parcl->semicolon_token.data = strdup(";");
- parcl->parcelable = true;
- doc = (document_item_type*)parcl;
- }
- else if (0 == strcmp("interface", type)) {
- interface_type* iface = (interface_type*)malloc(
- sizeof(interface_type));
- memset(iface, 0, sizeof(interface_type));
- iface->document_item.item_type = INTERFACE_TYPE_BINDER;
- iface->interface_token.lineno = lineno;
- iface->interface_token.data = strdup(type);
- iface->package = packagename ? strdup(packagename) : NULL;
- iface->name.lineno = lineno;
- iface->name.data = strdup(classname);
- iface->open_brace_token.lineno = lineno;
- iface->open_brace_token.data = strdup("{");
- iface->close_brace_token.lineno = lineno;
- iface->close_brace_token.data = strdup("}");
- doc = (document_item_type*)iface;
- }
- else {
- fprintf(stderr, "%s:%d: bad type in line: %s\n",
- filename.c_str(), lineno, line);
- fclose(f);
- return 1;
- }
- err = gather_types(filename.c_str(), doc);
- lineno++;
- }
-
- if (!feof(f)) {
- fprintf(stderr, "%s:%d: error reading file, line to long.\n",
- filename.c_str(), lineno);
- return 1;
- }
-
- fclose(f);
- return 0;
-}
-
-static int
-check_and_assign_method_ids(const char * filename, interface_item_type* first_item)
-{
- // Check whether there are any methods with manually assigned id's and any that are not.
- // Either all method id's must be manually assigned or all of them must not.
- // Also, check for duplicates of user set id's and that the id's are within the proper bounds.
- set<int> usedIds;
- interface_item_type* item = first_item;
- bool hasUnassignedIds = false;
- bool hasAssignedIds = false;
- while (item != NULL) {
- if (item->item_type == METHOD_TYPE) {
- method_type* method_item = (method_type*)item;
- if (method_item->hasId) {
- hasAssignedIds = true;
- method_item->assigned_id = atoi(method_item->id.data);
- // Ensure that the user set id is not duplicated.
- if (usedIds.find(method_item->assigned_id) != usedIds.end()) {
- // We found a duplicate id, so throw an error.
- fprintf(stderr,
- "%s:%d Found duplicate method id (%d) for method: %s\n",
- filename, method_item->id.lineno,
- method_item->assigned_id, method_item->name.data);
- return 1;
- }
- // Ensure that the user set id is within the appropriate limits
- if (method_item->assigned_id < MIN_USER_SET_METHOD_ID ||
- method_item->assigned_id > MAX_USER_SET_METHOD_ID) {
- fprintf(stderr, "%s:%d Found out of bounds id (%d) for method: %s\n",
- filename, method_item->id.lineno,
- method_item->assigned_id, method_item->name.data);
- fprintf(stderr, " Value for id must be between %d and %d inclusive.\n",
- MIN_USER_SET_METHOD_ID, MAX_USER_SET_METHOD_ID);
- return 1;
- }
- usedIds.insert(method_item->assigned_id);
- } else {
- hasUnassignedIds = true;
- }
- if (hasAssignedIds && hasUnassignedIds) {
- fprintf(stderr,
- "%s: You must either assign id's to all methods or to none of them.\n",
- filename);
- return 1;
- }
- }
- item = item->next;
- }
-
- // In the case that all methods have unassigned id's, set a unique id for them.
- if (hasUnassignedIds) {
- int newId = 0;
- item = first_item;
- while (item != NULL) {
- if (item->item_type == METHOD_TYPE) {
- method_type* method_item = (method_type*)item;
- method_item->assigned_id = newId++;
- }
- item = item->next;
- }
- }
-
- // success
- return 0;
-}
-
-// ==========================================================
-int
-compile_aidl(Options& options)
-{
- int err = 0, N;
-
- set_import_paths(options.importPaths);
-
- register_base_types();
-
- // import the preprocessed file
- N = options.preprocessedFiles.size();
- for (int i=0; i<N; i++) {
- const string& s = options.preprocessedFiles[i];
- err |= parse_preprocessed_file(s);
- }
- if (err != 0) {
- return err;
- }
-
- // parse the main file
- g_callbacks = &g_mainCallbacks;
- err = parse_aidl(options.inputFileName.c_str());
- document_item_type* mainDoc = g_document;
- g_document = NULL;
-
- // parse the imports
- g_callbacks = &g_mainCallbacks;
- import_info* import = g_imports;
- while (import) {
- if (NAMES.Find(import->neededClass) == NULL) {
- import->filename = find_import_file(import->neededClass);
- if (!import->filename) {
- fprintf(stderr, "%s:%d: couldn't find import for class %s\n",
- import->from, import->statement.lineno,
- import->neededClass);
- err |= 1;
- } else {
- err |= parse_aidl(import->filename);
- import->doc = g_document;
- if (import->doc == NULL) {
- err |= 1;
- }
- }
- }
- import = import->next;
- }
- // bail out now if parsing wasn't successful
- if (err != 0 || mainDoc == NULL) {
- //fprintf(stderr, "aidl: parsing failed, stopping.\n");
- return 1;
- }
-
- // complain about ones that aren't in the right files
- err |= check_filenames(options.inputFileName.c_str(), mainDoc);
- import = g_imports;
- while (import) {
- err |= check_filenames(import->filename, import->doc);
- import = import->next;
- }
-
- // gather the types that have been declared
- err |= gather_types(options.inputFileName.c_str(), mainDoc);
- import = g_imports;
- while (import) {
- err |= gather_types(import->filename, import->doc);
- import = import->next;
- }
-
-#if 0
- printf("---- main doc ----\n");
- test_document(mainDoc);
-
- import = g_imports;
- while (import) {
- printf("---- import doc ----\n");
- test_document(import->doc);
- import = import->next;
- }
- NAMES.Dump();
-#endif
-
- // check the referenced types in mainDoc to make sure we've imported them
- err |= check_types(options.inputFileName.c_str(), mainDoc);
-
- // finally, there really only needs to be one thing in mainDoc, and it
- // needs to be an interface.
- bool onlyParcelable = false;
- err |= exactly_one_interface(options.inputFileName.c_str(), mainDoc, options, &onlyParcelable);
-
- // If this includes an interface definition, then assign method ids and validate.
- if (!onlyParcelable) {
- err |= check_and_assign_method_ids(options.inputFileName.c_str(),
- ((interface_type*)mainDoc)->interface_items);
- }
-
- // after this, there shouldn't be any more errors because of the
- // input.
- if (err != 0 || mainDoc == NULL) {
- return 1;
- }
-
- // if needed, generate the outputFileName from the outputBaseFolder
- if (options.outputFileName.length() == 0 &&
- options.outputBaseFolder.length() > 0) {
- options.outputFileName = generate_outputFileName(options, mainDoc);
- }
-
- // if we were asked to, generate a make dependency file
- // unless it's a parcelable *and* it's supposed to fail on parcelable
- if ((options.autoDepFile || options.depFileName != "") &&
- !(onlyParcelable && options.failOnParcelable)) {
- // make sure the folders of the output file all exists
- check_outputFilePath(options.outputFileName);
- generate_dep_file(options, mainDoc);
- }
-
- // they didn't ask to fail on parcelables, so just exit quietly.
- if (onlyParcelable && !options.failOnParcelable) {
- return 0;
- }
-
- // make sure the folders of the output file all exists
- check_outputFilePath(options.outputFileName);
-
- err = generate_java(options.outputFileName, options.inputFileName.c_str(),
- (interface_type*)mainDoc);
-
- return err;
-}
-
-int
-preprocess_aidl(const Options& options)
-{
- vector<string> lines;
- int err;
-
- // read files
- int N = options.filesToPreprocess.size();
- for (int i=0; i<N; i++) {
- g_callbacks = &g_mainCallbacks;
- err = parse_aidl(options.filesToPreprocess[i].c_str());
- if (err != 0) {
- return err;
- }
- document_item_type* doc = g_document;
- string line;
- if (doc->item_type == USER_DATA_TYPE) {
- user_data_type* parcelable = (user_data_type*)doc;
- if (parcelable->parcelable) {
- line = "parcelable ";
- }
- if (parcelable->package) {
- line += parcelable->package;
- line += '.';
- }
- line += parcelable->name.data;
- } else {
- line = "interface ";
- interface_type* iface = (interface_type*)doc;
- if (iface->package) {
- line += iface->package;
- line += '.';
- }
- line += iface->name.data;
- }
- line += ";\n";
- lines.push_back(line);
- }
-
- // write preprocessed file
- int fd = open( options.outputFileName.c_str(),
- O_RDWR|O_CREAT|O_TRUNC|O_BINARY,
-#ifdef _WIN32
- _S_IREAD|_S_IWRITE);
-#else
- S_IRUSR|S_IWUSR|S_IRGRP);
-#endif
- if (fd == -1) {
- fprintf(stderr, "aidl: could not open file for write: %s\n",
- options.outputFileName.c_str());
- return 1;
- }
-
- N = lines.size();
- for (int i=0; i<N; i++) {
- const string& s = lines[i];
- int len = s.length();
- if (len != write(fd, s.c_str(), len)) {
- fprintf(stderr, "aidl: error writing to file %s\n",
- options.outputFileName.c_str());
- close(fd);
- unlink(options.outputFileName.c_str());
- return 1;
- }
- }
-
- close(fd);
- return 0;
-}
diff --git a/tools/aidl/aidl.h b/tools/aidl/aidl.h
deleted file mode 100644
index 98b15f36c21a..000000000000
--- a/tools/aidl/aidl.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef AIDL_AIDL_H_
-#define AIDL_AIDL_H_
-
-#include "options.h"
-
-int compile_aidl(Options& options);
-int preprocess_aidl(const Options& options);
-
-#endif // AIDL_AIDL_H_
diff --git a/tools/aidl/aidl_language.cpp b/tools/aidl/aidl_language.cpp
deleted file mode 100644
index 4eb3faecb574..000000000000
--- a/tools/aidl/aidl_language.cpp
+++ /dev/null
@@ -1,94 +0,0 @@
-#include "aidl_language.h"
-#include "aidl_language_y.hpp"
-#include <stdio.h>
-#include <stdlib.h>
-#include <string>
-#include <iostream>
-
-#ifdef _WIN32
-int isatty(int fd)
-{
- return (fd == 0);
-}
-#endif
-
-using std::string;
-using std::cerr;
-using std::endl;
-
-ParserCallbacks* g_callbacks = NULL; // &k_parserCallbacks;
-
-void yylex_init(void **);
-void yylex_destroy(void *);
-void yyset_in(FILE *f, void *);
-int yyparse(ParseState*);
-
-ParseState::ParseState() : ParseState("") {}
-
-ParseState::ParseState(const string& filename)
- : filename_(filename) {
- yylex_init(&scanner_);
-}
-
-ParseState::~ParseState() {
- yylex_destroy(scanner_);
-}
-
-string ParseState::FileName() {
- return filename_;
-}
-
-string ParseState::Package() {
- return g_currentPackage;
-}
-
-void ParseState::ProcessDocument(const document_item_type& items) {
- /* The cast is not my fault. I didn't write the code on the other side. */
- /* TODO(sadmac): b/23977313 */
- g_callbacks->document((document_item_type *)&items);
-}
-
-void ParseState::ProcessImport(const buffer_type& statement) {
- /* The cast is not my fault. I didn't write the code on the other side. */
- /* TODO(sadmac): b/23977313 */
- g_callbacks->import((buffer_type *)&statement);
-}
-
-void ParseState::ReportError(const string& err) {
- /* FIXME: We're printing out the line number as -1. We used to use yylineno
- * (which was NEVER correct even before reentrant parsing). Now we'll need
- * another way.
- */
- cerr << filename_ << ":" << -1 << ": " << err << endl;
- error_ = 1;
-}
-
-bool ParseState::FoundNoErrors() {
- return error_ == 0;
-}
-
-void *ParseState::Scanner() {
- return scanner_;
-}
-
-bool ParseState::OpenFileFromDisk() {
- FILE *in = fopen(FileName().c_str(), "r");
-
- if (! in)
- return false;
-
- yyset_in(in, Scanner());
- return true;
-}
-
-int ParseState::RunParser() {
- int ret = yy::parser(this).parse();
-
- free((void *)g_currentPackage);
- g_currentPackage = NULL;
-
- if (error_)
- return 1;
-
- return ret;
-}
diff --git a/tools/aidl/aidl_language.h b/tools/aidl/aidl_language.h
deleted file mode 100644
index f3a126e9f57a..000000000000
--- a/tools/aidl/aidl_language.h
+++ /dev/null
@@ -1,189 +0,0 @@
-#ifndef AIDL_AIDL_LANGUAGE_H_
-#define AIDL_AIDL_LANGUAGE_H_
-
-#include <string>
-
-#include "macros.h"
-
-typedef enum {
- NO_EXTRA_TEXT = 0,
- SHORT_COMMENT,
- LONG_COMMENT,
- COPY_TEXT,
- WHITESPACE
-} which_extra_text;
-
-typedef struct extra_text_type {
- unsigned lineno;
- which_extra_text which;
- char* data;
- unsigned len;
- struct extra_text_type* next;
-} extra_text_type;
-
-typedef struct buffer_type {
- unsigned lineno;
- unsigned token;
- char *data;
- extra_text_type* extra;
-} buffer_type;
-
-typedef struct type_type {
- buffer_type type;
- buffer_type array_token;
- int dimension;
-} type_type;
-
-typedef struct arg_type {
- buffer_type comma_token; // empty in the first one in the list
- buffer_type direction;
- type_type type;
- buffer_type name;
- struct arg_type *next;
-} arg_type;
-
-enum {
- METHOD_TYPE
-};
-
-typedef struct interface_item_type {
- unsigned item_type;
- struct interface_item_type* next;
-} interface_item_type;
-
-typedef struct method_type {
- interface_item_type interface_item;
- type_type type;
- bool oneway;
- buffer_type oneway_token;
- buffer_type name;
- buffer_type open_paren_token;
- arg_type* args;
- buffer_type close_paren_token;
- bool hasId;
- buffer_type equals_token;
- buffer_type id;
- // XXX missing comments/copy text here
- buffer_type semicolon_token;
- buffer_type* comments_token; // points into this structure, DO NOT DELETE
- int assigned_id;
-} method_type;
-
-enum {
- USER_DATA_TYPE = 12,
- INTERFACE_TYPE_BINDER
-};
-
-typedef struct document_item_type {
- unsigned item_type;
- struct document_item_type* next;
-} document_item_type;
-
-
-typedef struct user_data_type {
- document_item_type document_item;
- buffer_type keyword_token; // only the first one
- char* package;
- buffer_type name;
- buffer_type semicolon_token;
- bool parcelable;
-} user_data_type;
-
-typedef struct interface_type {
- document_item_type document_item;
- buffer_type interface_token;
- bool oneway;
- buffer_type oneway_token;
- char* package;
- buffer_type name;
- buffer_type open_brace_token;
- interface_item_type* interface_items;
- buffer_type close_brace_token;
- buffer_type* comments_token; // points into this structure, DO NOT DELETE
-} interface_type;
-
-typedef union lexer_type {
- buffer_type buffer;
- type_type type;
- arg_type *arg;
- method_type* method;
- interface_item_type* interface_item;
- interface_type* interface_obj;
- user_data_type* user_data;
- document_item_type* document_item;
-} lexer_type;
-
-
-#define YYSTYPE lexer_type
-
-#if __cplusplus
-extern "C" {
-#endif
-
-int parse_aidl(char const *);
-
-// strips off the leading whitespace, the "import" text
-// also returns whether it's a local or system import
-// we rely on the input matching the import regex from below
-char* parse_import_statement(const char* text);
-
-// in, out or inout
-enum {
- IN_PARAMETER = 1,
- OUT_PARAMETER = 2,
- INOUT_PARAMETER = 3
-};
-int convert_direction(const char* direction);
-
-// callbacks from within the parser
-// these functions all take ownership of the strings
-typedef struct ParserCallbacks {
- void (*document)(document_item_type* items);
- void (*import)(buffer_type* statement);
-} ParserCallbacks;
-
-extern ParserCallbacks* g_callbacks;
-
-// the package name for our current file
-extern char const* g_currentPackage;
-
-typedef enum {
- STATEMENT_INSIDE_INTERFACE
-} error_type;
-
-void init_buffer_type(buffer_type* buf, int lineno);
-
-
-class ParseState {
- public:
- ParseState();
- ParseState(const std::string& filename);
- ~ParseState();
-
- bool OpenFileFromDisk();
- int RunParser();
- void ReportError(const std::string& err);
-
- bool FoundNoErrors();
- std::string FileName();
- std::string Package();
- void *Scanner();
-
- void ProcessDocument(const document_item_type& items);
- void ProcessImport(const buffer_type& statement);
-
- private:
- int error_ = 0;
- std::string filename_;
- std::string package_;
- void *scanner_ = nullptr;
-
- DISALLOW_COPY_AND_ASSIGN(ParseState);
-};
-
-#if __cplusplus
-}
-#endif
-
-
-#endif // AIDL_AIDL_LANGUAGE_H_
diff --git a/tools/aidl/aidl_language_l.l b/tools/aidl/aidl_language_l.l
deleted file mode 100644
index 540b550035ff..000000000000
--- a/tools/aidl/aidl_language_l.l
+++ /dev/null
@@ -1,196 +0,0 @@
-%{
-#include "aidl_language.h"
-#include "aidl_language_y.hpp"
-#include "search_path.h"
-#include <string.h>
-#include <stdlib.h>
-
-extern YYSTYPE yylval;
-
-// comment and whitespace handling
-// these functions save a copy of the buffer
-static void begin_extra_text(unsigned lineno, which_extra_text which);
-static void append_extra_text(char* text);
-static extra_text_type* get_extra_text(void); // you now own the object
- // this returns
-static void drop_extra_text(void);
-
-// package handling
-static void do_package_statement(const char* importText);
-
-#define SET_BUFFER(t) \
- do { \
- yylval->buffer.lineno = yyget_lineno(yyscanner); \
- yylval->buffer.token = (t); \
- yylval->buffer.data = strdup(yytext); \
- yylval->buffer.extra = get_extra_text(); \
- } while(0)
-
-%}
-
-%option yylineno
-%option noyywrap
-%option reentrant
-%option bison-bridge
-%option bison-locations
-
-%x COPYING LONG_COMMENT
-
-identifier [_a-zA-Z][_a-zA-Z0-9\.]*
-whitespace ([ \t\n\r]+)
-brackets \[{whitespace}?\]
-idvalue (0|[1-9][0-9]*)
-
-%%
-
-
-\%\%\{ { begin_extra_text(yylineno, COPY_TEXT); BEGIN(COPYING); }
-<COPYING>\}\%\% { BEGIN(INITIAL); }
-<COPYING>.*\n { append_extra_text(yytext); }
-<COPYING>.* { append_extra_text(yytext); }
-<COPYING>\n+ { append_extra_text(yytext); }
-
-
-\/\* { begin_extra_text(yylineno, (which_extra_text)LONG_COMMENT);
- BEGIN(LONG_COMMENT); }
-<LONG_COMMENT>[^*]* { append_extra_text(yytext); }
-<LONG_COMMENT>\*+[^/] { append_extra_text(yytext); }
-<LONG_COMMENT>\n { append_extra_text(yytext); }
-<LONG_COMMENT>\**\/ { BEGIN(INITIAL); }
-
-^{whitespace}?import{whitespace}[^ \t\r\n]+{whitespace}?; {
- SET_BUFFER(yy::parser::token::IMPORT);
- return yy::parser::token::IMPORT;
- }
-^{whitespace}?package{whitespace}[^ \t\r\n]+{whitespace}?; {
- do_package_statement(yytext);
- SET_BUFFER(yy::parser::token::PACKAGE);
- return yy::parser::token::PACKAGE;
- }
-<<EOF>> { yyterminate(); }
-
-\/\/.*\n { begin_extra_text(yylineno, SHORT_COMMENT);
- append_extra_text(yytext); }
-
-{whitespace} { /* begin_extra_text(yylineno, WHITESPACE);
- append_extra_text(yytext); */ }
-
-; { SET_BUFFER(';'); return ';'; }
-\{ { SET_BUFFER('{'); return '{'; }
-\} { SET_BUFFER('}'); return '}'; }
-\( { SET_BUFFER('('); return '('; }
-\) { SET_BUFFER(')'); return ')'; }
-, { SET_BUFFER(','); return ','; }
-= { SET_BUFFER('='); return '='; }
-
- /* keywords */
-parcelable { SET_BUFFER(yy::parser::token::PARCELABLE); return yy::parser::token::PARCELABLE; }
-interface { SET_BUFFER(yy::parser::token::INTERFACE); return yy::parser::token::INTERFACE; }
-in { SET_BUFFER(yy::parser::token::IN); return yy::parser::token::IN; }
-out { SET_BUFFER(yy::parser::token::OUT); return yy::parser::token::OUT; }
-inout { SET_BUFFER(yy::parser::token::INOUT); return yy::parser::token::INOUT; }
-oneway { SET_BUFFER(yy::parser::token::ONEWAY); return yy::parser::token::ONEWAY; }
-
-{brackets}+ { SET_BUFFER(yy::parser::token::ARRAY); return yy::parser::token::ARRAY; }
-{idvalue} { SET_BUFFER(yy::parser::token::IDVALUE); return yy::parser::token::IDVALUE; }
-{identifier} { SET_BUFFER(yy::parser::token::IDENTIFIER); return yy::parser::token::IDENTIFIER; }
-{identifier}\<{whitespace}*{identifier}({whitespace}*,{whitespace}*{identifier})*{whitespace}*\> {
- SET_BUFFER(yy::parser::token::GENERIC); return yy::parser::token::GENERIC; }
-
- /* syntax error! */
-. { printf("UNKNOWN(%s)", yytext);
- yylval->buffer.lineno = yylineno;
- yylval->buffer.token = yy::parser::token::IDENTIFIER;
- yylval->buffer.data = strdup(yytext);
- return yy::parser::token::IDENTIFIER;
- }
-
-%%
-
-// comment and whitespace handling
-// ================================================
-extra_text_type* g_extraText = NULL;
-extra_text_type* g_nextExtraText = NULL;
-
-void begin_extra_text(unsigned lineno, which_extra_text which)
-{
- extra_text_type* text = (extra_text_type*)malloc(sizeof(extra_text_type));
- text->lineno = lineno;
- text->which = which;
- text->data = NULL;
- text->len = 0;
- text->next = NULL;
- if (g_nextExtraText == NULL) {
- g_extraText = text;
- } else {
- g_nextExtraText->next = text;
- }
- g_nextExtraText = text;
-}
-
-void append_extra_text(char* text)
-{
- if (g_nextExtraText->data == NULL) {
- g_nextExtraText->data = strdup(text);
- g_nextExtraText->len = strlen(text);
- } else {
- char* orig = g_nextExtraText->data;
- unsigned oldLen = g_nextExtraText->len;
- unsigned len = strlen(text);
- g_nextExtraText->len += len;
- g_nextExtraText->data = (char*)malloc(g_nextExtraText->len+1);
- memcpy(g_nextExtraText->data, orig, oldLen);
- memcpy(g_nextExtraText->data+oldLen, text, len);
- g_nextExtraText->data[g_nextExtraText->len] = '\0';
- free(orig);
- }
-}
-
-extra_text_type*
-get_extra_text(void)
-{
- extra_text_type* result = g_extraText;
- g_extraText = NULL;
- g_nextExtraText = NULL;
- return result;
-}
-
-void drop_extra_text(void)
-{
- extra_text_type* p = g_extraText;
- while (p) {
- extra_text_type* next = p->next;
- free(p->data);
- free(p);
- free(next);
- }
- g_extraText = NULL;
- g_nextExtraText = NULL;
-}
-
-
-// package handling
-// ================================================
-void do_package_statement(const char* importText)
-{
- if (g_currentPackage) free((void*)g_currentPackage);
- g_currentPackage = parse_import_statement(importText);
-}
-
-
-// main parse function
-// ================================================
-extern ParseState *psGlobal;
-char const* g_currentPackage = NULL;
-
-int parse_aidl(char const *filename) {
- ParseState ps(filename);
- psGlobal = &ps;
-
- if (!ps.OpenFileFromDisk()) {
- fprintf(stderr, "aidl: unable to open file for read: %s\n", filename);
- return 1;
- }
-
- return ps.RunParser();
-}
diff --git a/tools/aidl/aidl_language_y.y b/tools/aidl/aidl_language_y.y
deleted file mode 100644
index 7a2b78514ba4..000000000000
--- a/tools/aidl/aidl_language_y.y
+++ /dev/null
@@ -1,343 +0,0 @@
-%{
-#include "aidl_language.h"
-#include "aidl_language_y.hpp"
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-int yylex(lexer_type *, yy::parser::location_type *l, void *);
-
-static int count_brackets(const char*);
-
-#define lex_scanner ps->Scanner()
-
-%}
-
-%parse-param { ParseState* ps }
-%lex-param { void *lex_scanner }
-
-%pure-parser
-%skeleton "glr.cc"
-
-%token IMPORT
-%token PACKAGE
-%token IDENTIFIER
-%token IDVALUE
-%token GENERIC
-%token ARRAY
-%token PARCELABLE
-%token INTERFACE
-%token IN
-%token OUT
-%token INOUT
-%token ONEWAY
-
-%%
-document:
- document_items { ps->ProcessDocument(*$1.document_item); }
- | headers document_items { ps->ProcessDocument(*$2.document_item); }
- ;
-
-headers:
- package { }
- | imports { }
- | package imports { }
- ;
-
-package:
- PACKAGE { }
- ;
-
-imports:
- IMPORT { ps->ProcessImport($1.buffer); }
- | IMPORT imports { ps->ProcessImport($1.buffer); }
- ;
-
-document_items:
- { $$.document_item = NULL; }
- | document_items declaration {
- if ($2.document_item == NULL) {
- // error cases only
- $$ = $1;
- } else {
- document_item_type* p = $1.document_item;
- while (p && p->next) {
- p=p->next;
- }
- if (p) {
- p->next = (document_item_type*)$2.document_item;
- $$ = $1;
- } else {
- $$.document_item = (document_item_type*)$2.document_item;
- }
- }
- }
- | document_items error {
- fprintf(stderr, "%s:%d: syntax error don't know what to do with \"%s\"\n",
- ps->FileName().c_str(),
- $2.buffer.lineno, $2.buffer.data);
- $$ = $1;
- }
- ;
-
-declaration:
- parcelable_decl { $$.document_item = (document_item_type*)$1.user_data; }
- | interface_decl { $$.document_item = (document_item_type*)$1.interface_item; }
- ;
-
-parcelable_decl:
- PARCELABLE IDENTIFIER ';' {
- user_data_type* b = (user_data_type*)malloc(sizeof(user_data_type));
- b->document_item.item_type = USER_DATA_TYPE;
- b->document_item.next = NULL;
- b->keyword_token = $1.buffer;
- b->name = $2.buffer;
- b->package =
- strdup(ps->Package().c_str());
- b->semicolon_token = $3.buffer;
- b->parcelable = true;
- $$.user_data = b;
- }
- | PARCELABLE ';' {
- fprintf(stderr, "%s:%d syntax error in parcelable declaration. Expected type name.\n",
- ps->FileName().c_str(), $1.buffer.lineno);
- $$.user_data = NULL;
- }
- | PARCELABLE error ';' {
- fprintf(stderr, "%s:%d syntax error in parcelable declaration. Expected type name, saw \"%s\".\n",
- ps->FileName().c_str(), $2.buffer.lineno, $2.buffer.data);
- $$.user_data = NULL;
- }
- ;
-
-interface_header:
- INTERFACE {
- interface_type* c = (interface_type*)malloc(sizeof(interface_type));
- c->document_item.item_type = INTERFACE_TYPE_BINDER;
- c->document_item.next = NULL;
- c->interface_token = $1.buffer;
- c->oneway = false;
- memset(&c->oneway_token, 0, sizeof(buffer_type));
- c->comments_token = &c->interface_token;
- $$.interface_obj = c;
- }
- | ONEWAY INTERFACE {
- interface_type* c = (interface_type*)malloc(sizeof(interface_type));
- c->document_item.item_type = INTERFACE_TYPE_BINDER;
- c->document_item.next = NULL;
- c->interface_token = $2.buffer;
- c->oneway = true;
- c->oneway_token = $1.buffer;
- c->comments_token = &c->oneway_token;
- $$.interface_obj = c;
- }
- ;
-
-interface_decl:
- interface_header IDENTIFIER '{' interface_items '}' {
- interface_type* c = $1.interface_obj;
- c->name = $2.buffer;
- c->package =
- strdup(ps->Package().c_str());
- c->open_brace_token = $3.buffer;
- c->interface_items = $4.interface_item;
- c->close_brace_token = $5.buffer;
- $$.interface_obj = c;
- }
- | INTERFACE error '{' interface_items '}' {
- fprintf(stderr, "%s:%d: syntax error in interface declaration. Expected type name, saw \"%s\"\n",
- ps->FileName().c_str(), $2.buffer.lineno, $2.buffer.data);
- $$.document_item = NULL;
- }
- | INTERFACE error '}' {
- fprintf(stderr, "%s:%d: syntax error in interface declaration. Expected type name, saw \"%s\"\n",
- ps->FileName().c_str(), $2.buffer.lineno, $2.buffer.data);
- $$.document_item = NULL;
- }
-
- ;
-
-interface_items:
- { $$.interface_item = NULL; }
- | interface_items method_decl {
- interface_item_type* p=$1.interface_item;
- while (p && p->next) {
- p=p->next;
- }
- if (p) {
- p->next = (interface_item_type*)$2.method;
- $$ = $1;
- } else {
- $$.interface_item = (interface_item_type*)$2.method;
- }
- }
- | interface_items error ';' {
- fprintf(stderr, "%s:%d: syntax error before ';' (expected method declaration)\n",
- ps->FileName().c_str(), $3.buffer.lineno);
- $$ = $1;
- }
- ;
-
-method_decl:
- type IDENTIFIER '(' arg_list ')' ';' {
- method_type *method = (method_type*)malloc(sizeof(method_type));
- method->interface_item.item_type = METHOD_TYPE;
- method->interface_item.next = NULL;
- method->oneway = false;
- method->type = $1.type;
- memset(&method->oneway_token, 0, sizeof(buffer_type));
- method->name = $2.buffer;
- method->open_paren_token = $3.buffer;
- method->args = $4.arg;
- method->close_paren_token = $5.buffer;
- method->hasId = false;
- memset(&method->equals_token, 0, sizeof(buffer_type));
- memset(&method->id, 0, sizeof(buffer_type));
- method->semicolon_token = $6.buffer;
- method->comments_token = &method->type.type;
- $$.method = method;
- }
- | ONEWAY type IDENTIFIER '(' arg_list ')' ';' {
- method_type *method = (method_type*)malloc(sizeof(method_type));
- method->interface_item.item_type = METHOD_TYPE;
- method->interface_item.next = NULL;
- method->oneway = true;
- method->oneway_token = $1.buffer;
- method->type = $2.type;
- method->name = $3.buffer;
- method->open_paren_token = $4.buffer;
- method->args = $5.arg;
- method->close_paren_token = $6.buffer;
- method->hasId = false;
- memset(&method->equals_token, 0, sizeof(buffer_type));
- memset(&method->id, 0, sizeof(buffer_type));
- method->semicolon_token = $7.buffer;
- method->comments_token = &method->oneway_token;
- $$.method = method;
- }
- | type IDENTIFIER '(' arg_list ')' '=' IDVALUE ';' {
- method_type *method = (method_type*)malloc(sizeof(method_type));
- method->interface_item.item_type = METHOD_TYPE;
- method->interface_item.next = NULL;
- method->oneway = false;
- memset(&method->oneway_token, 0, sizeof(buffer_type));
- method->type = $1.type;
- method->name = $2.buffer;
- method->open_paren_token = $3.buffer;
- method->args = $4.arg;
- method->close_paren_token = $5.buffer;
- method->hasId = true;
- method->equals_token = $6.buffer;
- method->id = $7.buffer;
- method->semicolon_token = $8.buffer;
- method->comments_token = &method->type.type;
- $$.method = method;
- }
- | ONEWAY type IDENTIFIER '(' arg_list ')' '=' IDVALUE ';' {
- method_type *method = (method_type*)malloc(sizeof(method_type));
- method->interface_item.item_type = METHOD_TYPE;
- method->interface_item.next = NULL;
- method->oneway = true;
- method->oneway_token = $1.buffer;
- method->type = $2.type;
- method->name = $3.buffer;
- method->open_paren_token = $4.buffer;
- method->args = $5.arg;
- method->close_paren_token = $6.buffer;
- method->hasId = true;
- method->equals_token = $7.buffer;
- method->id = $8.buffer;
- method->semicolon_token = $9.buffer;
- method->comments_token = &method->oneway_token;
- $$.method = method;
- }
- ;
-
-arg_list:
- { $$.arg = NULL; }
- | arg { $$ = $1; }
- | arg_list ',' arg {
- if ($$.arg != NULL) {
- // only NULL on error
- $$ = $1;
- arg_type *p = $1.arg;
- while (p && p->next) {
- p=p->next;
- }
- $3.arg->comma_token = $2.buffer;
- p->next = $3.arg;
- }
- }
- | error {
- fprintf(stderr, "%s:%d: syntax error in parameter list\n",
- ps->FileName().c_str(), $1.buffer.lineno);
- $$.arg = NULL;
- }
- ;
-
-arg:
- direction type IDENTIFIER {
- arg_type* arg = (arg_type*)malloc(sizeof(arg_type));
- memset(&arg->comma_token, 0, sizeof(buffer_type));
- arg->direction = $1.buffer;
- arg->type = $2.type;
- arg->name = $3.buffer;
- arg->next = NULL;
- $$.arg = arg;
- }
- ;
-
-type:
- IDENTIFIER {
- $$.type.type = $1.buffer;
- init_buffer_type(&$$.type.array_token,
- $1.buffer.lineno);
- $$.type.dimension = 0;
- }
- | IDENTIFIER ARRAY {
- $$.type.type = $1.buffer;
- $$.type.array_token = $2.buffer;
- $$.type.dimension = count_brackets($2.buffer.data);
- }
- | GENERIC {
- $$.type.type = $1.buffer;
- init_buffer_type(&$$.type.array_token,
- $1.buffer.lineno);
- $$.type.dimension = 0;
- }
- ;
-
-direction:
- { init_buffer_type(&$$.buffer, $$.buffer.lineno); }
- | IN { $$.buffer = $1.buffer; }
- | OUT { $$.buffer = $1.buffer; }
- | INOUT { $$.buffer = $1.buffer; }
- ;
-
-%%
-
-#include <ctype.h>
-#include <stdio.h>
-
-void init_buffer_type(buffer_type* buf, int lineno)
-{
- buf->lineno = lineno;
- buf->token = 0;
- buf->data = NULL;
- buf->extra = NULL;
-}
-
-static int count_brackets(const char* s)
-{
- int n=0;
- while (*s) {
- if (*s == '[') n++;
- s++;
- }
- return n;
-}
-
-void yy::parser::error(const yy::parser::location_type& l, const std::string& errstr)
-{
- ps->ReportError(errstr);
-}
diff --git a/tools/aidl/generate_java.cpp b/tools/aidl/generate_java.cpp
deleted file mode 100644
index 15093406da6c..000000000000
--- a/tools/aidl/generate_java.cpp
+++ /dev/null
@@ -1,96 +0,0 @@
-#include "generate_java.h"
-#include "Type.h"
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-// =================================================
-VariableFactory::VariableFactory(const string& base)
- :m_base(base),
- m_index(0)
-{
-}
-
-Variable*
-VariableFactory::Get(Type* type)
-{
- char name[100];
- sprintf(name, "%s%d", m_base.c_str(), m_index);
- m_index++;
- Variable* v = new Variable(type, name);
- m_vars.push_back(v);
- return v;
-}
-
-Variable*
-VariableFactory::Get(int index)
-{
- return m_vars[index];
-}
-
-// =================================================
-string
-gather_comments(extra_text_type* extra)
-{
- string s;
- while (extra) {
- if (extra->which == SHORT_COMMENT) {
- s += extra->data;
- }
- else if (extra->which == LONG_COMMENT) {
- s += "/*";
- s += extra->data;
- s += "*/";
- }
- extra = extra->next;
- }
- return s;
-}
-
-string
-append(const char* a, const char* b)
-{
- string s = a;
- s += b;
- return s;
-}
-
-// =================================================
-int
-generate_java(const string& filename, const string& originalSrc,
- interface_type* iface)
-{
- Class* cl;
-
- if (iface->document_item.item_type == INTERFACE_TYPE_BINDER) {
- cl = generate_binder_interface_class(iface);
- }
-
- Document* document = new Document;
- document->comment = "";
- if (iface->package) document->package = iface->package;
- document->originalSrc = originalSrc;
- document->classes.push_back(cl);
-
-// printf("outputting... filename=%s\n", filename.c_str());
- FILE* to;
- if (filename == "-") {
- to = stdout;
- } else {
- /* open file in binary mode to ensure that the tool produces the
- * same output on all platforms !!
- */
- to = fopen(filename.c_str(), "wb");
- if (to == NULL) {
- fprintf(stderr, "unable to open %s for write\n", filename.c_str());
- return 1;
- }
- }
-
- document->Write(to);
-
- fclose(to);
- return 0;
-}
-
diff --git a/tools/aidl/generate_java.h b/tools/aidl/generate_java.h
deleted file mode 100644
index 4e797436da0b..000000000000
--- a/tools/aidl/generate_java.h
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef AIDL_GENERATE_JAVA_H_
-#define AIDL_GENERATE_JAVA_H_
-
-#include "aidl_language.h"
-#include "AST.h"
-
-#include <string>
-
-using namespace std;
-
-int generate_java(const string& filename, const string& originalSrc,
- interface_type* iface);
-
-Class* generate_binder_interface_class(const interface_type* iface);
-
-string gather_comments(extra_text_type* extra);
-string append(const char* a, const char* b);
-
-class VariableFactory
-{
-public:
- VariableFactory(const string& base); // base must be short
- Variable* Get(Type* type);
- Variable* Get(int index);
-private:
- vector<Variable*> m_vars;
- string m_base;
- int m_index;
-};
-
-#endif // AIDL_GENERATE_JAVA_H_
-
diff --git a/tools/aidl/generate_java_binder.cpp b/tools/aidl/generate_java_binder.cpp
deleted file mode 100644
index f291ceb2b09f..000000000000
--- a/tools/aidl/generate_java_binder.cpp
+++ /dev/null
@@ -1,560 +0,0 @@
-#include "generate_java.h"
-#include "Type.h"
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-// =================================================
-class StubClass : public Class
-{
-public:
- StubClass(Type* type, Type* interfaceType);
- virtual ~StubClass();
-
- Variable* transact_code;
- Variable* transact_data;
- Variable* transact_reply;
- Variable* transact_flags;
- SwitchStatement* transact_switch;
-private:
- void make_as_interface(Type* interfaceType);
-};
-
-StubClass::StubClass(Type* type, Type* interfaceType)
- :Class()
-{
- this->comment = "/** Local-side IPC implementation stub class. */";
- this->modifiers = PUBLIC | ABSTRACT | STATIC;
- this->what = Class::CLASS;
- this->type = type;
- this->extends = BINDER_NATIVE_TYPE;
- this->interfaces.push_back(interfaceType);
-
- // descriptor
- Field* descriptor = new Field(STATIC | FINAL | PRIVATE,
- new Variable(STRING_TYPE, "DESCRIPTOR"));
- descriptor->value = "\"" + interfaceType->QualifiedName() + "\"";
- this->elements.push_back(descriptor);
-
- // ctor
- Method* ctor = new Method;
- ctor->modifiers = PUBLIC;
- ctor->comment = "/** Construct the stub at attach it to the "
- "interface. */";
- ctor->name = "Stub";
- ctor->statements = new StatementBlock;
- MethodCall* attach = new MethodCall(THIS_VALUE, "attachInterface",
- 2, THIS_VALUE, new LiteralExpression("DESCRIPTOR"));
- ctor->statements->Add(attach);
- this->elements.push_back(ctor);
-
- // asInterface
- make_as_interface(interfaceType);
-
- // asBinder
- Method* asBinder = new Method;
- asBinder->modifiers = PUBLIC | OVERRIDE;
- asBinder->returnType = IBINDER_TYPE;
- asBinder->name = "asBinder";
- asBinder->statements = new StatementBlock;
- asBinder->statements->Add(new ReturnStatement(THIS_VALUE));
- this->elements.push_back(asBinder);
-
- // onTransact
- this->transact_code = new Variable(INT_TYPE, "code");
- this->transact_data = new Variable(PARCEL_TYPE, "data");
- this->transact_reply = new Variable(PARCEL_TYPE, "reply");
- this->transact_flags = new Variable(INT_TYPE, "flags");
- Method* onTransact = new Method;
- onTransact->modifiers = PUBLIC | OVERRIDE;
- onTransact->returnType = BOOLEAN_TYPE;
- onTransact->name = "onTransact";
- onTransact->parameters.push_back(this->transact_code);
- onTransact->parameters.push_back(this->transact_data);
- onTransact->parameters.push_back(this->transact_reply);
- onTransact->parameters.push_back(this->transact_flags);
- onTransact->statements = new StatementBlock;
- onTransact->exceptions.push_back(REMOTE_EXCEPTION_TYPE);
- this->elements.push_back(onTransact);
- this->transact_switch = new SwitchStatement(this->transact_code);
-
- onTransact->statements->Add(this->transact_switch);
- MethodCall* superCall = new MethodCall(SUPER_VALUE, "onTransact", 4,
- this->transact_code, this->transact_data,
- this->transact_reply, this->transact_flags);
- onTransact->statements->Add(new ReturnStatement(superCall));
-}
-
-StubClass::~StubClass()
-{
-}
-
-void
-StubClass::make_as_interface(Type *interfaceType)
-{
- Variable* obj = new Variable(IBINDER_TYPE, "obj");
-
- Method* m = new Method;
- m->comment = "/**\n * Cast an IBinder object into an ";
- m->comment += interfaceType->QualifiedName();
- m->comment += " interface,\n";
- m->comment += " * generating a proxy if needed.\n */";
- m->modifiers = PUBLIC | STATIC;
- m->returnType = interfaceType;
- m->name = "asInterface";
- m->parameters.push_back(obj);
- m->statements = new StatementBlock;
-
- IfStatement* ifstatement = new IfStatement();
- ifstatement->expression = new Comparison(obj, "==", NULL_VALUE);
- ifstatement->statements = new StatementBlock;
- ifstatement->statements->Add(new ReturnStatement(NULL_VALUE));
- m->statements->Add(ifstatement);
-
- // IInterface iin = obj.queryLocalInterface(DESCRIPTOR)
- MethodCall* queryLocalInterface = new MethodCall(obj, "queryLocalInterface");
- queryLocalInterface->arguments.push_back(new LiteralExpression("DESCRIPTOR"));
- IInterfaceType* iinType = new IInterfaceType();
- Variable *iin = new Variable(iinType, "iin");
- VariableDeclaration* iinVd = new VariableDeclaration(iin, queryLocalInterface, NULL);
- m->statements->Add(iinVd);
-
- // Ensure the instance type of the local object is as expected.
- // One scenario where this is needed is if another package (with a
- // different class loader) runs in the same process as the service.
-
- // if (iin != null && iin instanceof <interfaceType>) return (<interfaceType>) iin;
- Comparison* iinNotNull = new Comparison(iin, "!=", NULL_VALUE);
- Comparison* instOfCheck = new Comparison(iin, " instanceof ",
- new LiteralExpression(interfaceType->QualifiedName()));
- IfStatement* instOfStatement = new IfStatement();
- instOfStatement->expression = new Comparison(iinNotNull, "&&", instOfCheck);
- instOfStatement->statements = new StatementBlock;
- instOfStatement->statements->Add(new ReturnStatement(new Cast(interfaceType, iin)));
- m->statements->Add(instOfStatement);
-
- string proxyType = interfaceType->QualifiedName();
- proxyType += ".Stub.Proxy";
- NewExpression* ne = new NewExpression(NAMES.Find(proxyType));
- ne->arguments.push_back(obj);
- m->statements->Add(new ReturnStatement(ne));
-
- this->elements.push_back(m);
-}
-
-
-
-// =================================================
-class ProxyClass : public Class
-{
-public:
- ProxyClass(Type* type, InterfaceType* interfaceType);
- virtual ~ProxyClass();
-
- Variable* mRemote;
- bool mOneWay;
-};
-
-ProxyClass::ProxyClass(Type* type, InterfaceType* interfaceType)
- :Class()
-{
- this->modifiers = PRIVATE | STATIC;
- this->what = Class::CLASS;
- this->type = type;
- this->interfaces.push_back(interfaceType);
-
- mOneWay = interfaceType->OneWay();
-
- // IBinder mRemote
- mRemote = new Variable(IBINDER_TYPE, "mRemote");
- this->elements.push_back(new Field(PRIVATE, mRemote));
-
- // Proxy()
- Variable* remote = new Variable(IBINDER_TYPE, "remote");
- Method* ctor = new Method;
- ctor->name = "Proxy";
- ctor->statements = new StatementBlock;
- ctor->parameters.push_back(remote);
- ctor->statements->Add(new Assignment(mRemote, remote));
- this->elements.push_back(ctor);
-
- // IBinder asBinder()
- Method* asBinder = new Method;
- asBinder->modifiers = PUBLIC | OVERRIDE;
- asBinder->returnType = IBINDER_TYPE;
- asBinder->name = "asBinder";
- asBinder->statements = new StatementBlock;
- asBinder->statements->Add(new ReturnStatement(mRemote));
- this->elements.push_back(asBinder);
-}
-
-ProxyClass::~ProxyClass()
-{
-}
-
-// =================================================
-static void
-generate_new_array(Type* t, StatementBlock* addTo, Variable* v,
- Variable* parcel)
-{
- Variable* len = new Variable(INT_TYPE, v->name + "_length");
- addTo->Add(new VariableDeclaration(len, new MethodCall(parcel, "readInt")));
- IfStatement* lencheck = new IfStatement();
- lencheck->expression = new Comparison(len, "<", new LiteralExpression("0"));
- lencheck->statements->Add(new Assignment(v, NULL_VALUE));
- lencheck->elseif = new IfStatement();
- lencheck->elseif->statements->Add(new Assignment(v,
- new NewArrayExpression(t, len)));
- addTo->Add(lencheck);
-}
-
-static void
-generate_write_to_parcel(Type* t, StatementBlock* addTo, Variable* v,
- Variable* parcel, int flags)
-{
- if (v->dimension == 0) {
- t->WriteToParcel(addTo, v, parcel, flags);
- }
- if (v->dimension == 1) {
- t->WriteArrayToParcel(addTo, v, parcel, flags);
- }
-}
-
-static void
-generate_create_from_parcel(Type* t, StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl)
-{
- if (v->dimension == 0) {
- t->CreateFromParcel(addTo, v, parcel, cl);
- }
- if (v->dimension == 1) {
- t->CreateArrayFromParcel(addTo, v, parcel, cl);
- }
-}
-
-static void
-generate_read_from_parcel(Type* t, StatementBlock* addTo, Variable* v,
- Variable* parcel, Variable** cl)
-{
- if (v->dimension == 0) {
- t->ReadFromParcel(addTo, v, parcel, cl);
- }
- if (v->dimension == 1) {
- t->ReadArrayFromParcel(addTo, v, parcel, cl);
- }
-}
-
-
-static void
-generate_method(const method_type* method, Class* interface,
- StubClass* stubClass, ProxyClass* proxyClass, int index)
-{
- arg_type* arg;
- int i;
- bool hasOutParams = false;
-
- const bool oneway = proxyClass->mOneWay || method->oneway;
-
- // == the TRANSACT_ constant =============================================
- string transactCodeName = "TRANSACTION_";
- transactCodeName += method->name.data;
-
- char transactCodeValue[60];
- sprintf(transactCodeValue, "(android.os.IBinder.FIRST_CALL_TRANSACTION + %d)", index);
-
- Field* transactCode = new Field(STATIC | FINAL,
- new Variable(INT_TYPE, transactCodeName));
- transactCode->value = transactCodeValue;
- stubClass->elements.push_back(transactCode);
-
- // == the declaration in the interface ===================================
- Method* decl = new Method;
- decl->comment = gather_comments(method->comments_token->extra);
- decl->modifiers = PUBLIC;
- decl->returnType = NAMES.Search(method->type.type.data);
- decl->returnTypeDimension = method->type.dimension;
- decl->name = method->name.data;
-
- arg = method->args;
- while (arg != NULL) {
- decl->parameters.push_back(new Variable(
- NAMES.Search(arg->type.type.data), arg->name.data,
- arg->type.dimension));
- arg = arg->next;
- }
-
- decl->exceptions.push_back(REMOTE_EXCEPTION_TYPE);
-
- interface->elements.push_back(decl);
-
- // == the stub method ====================================================
-
- Case* c = new Case(transactCodeName);
-
- MethodCall* realCall = new MethodCall(THIS_VALUE, method->name.data);
-
- // interface token validation is the very first thing we do
- c->statements->Add(new MethodCall(stubClass->transact_data,
- "enforceInterface", 1, new LiteralExpression("DESCRIPTOR")));
-
- // args
- Variable* cl = NULL;
- VariableFactory stubArgs("_arg");
- arg = method->args;
- while (arg != NULL) {
- Type* t = NAMES.Search(arg->type.type.data);
- Variable* v = stubArgs.Get(t);
- v->dimension = arg->type.dimension;
-
- c->statements->Add(new VariableDeclaration(v));
-
- if (convert_direction(arg->direction.data) & IN_PARAMETER) {
- generate_create_from_parcel(t, c->statements, v,
- stubClass->transact_data, &cl);
- } else {
- if (arg->type.dimension == 0) {
- c->statements->Add(new Assignment(v, new NewExpression(v->type)));
- }
- else if (arg->type.dimension == 1) {
- generate_new_array(v->type, c->statements, v,
- stubClass->transact_data);
- }
- else {
- fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__,
- __LINE__);
- }
- }
-
- realCall->arguments.push_back(v);
-
- arg = arg->next;
- }
-
- // the real call
- Variable* _result = NULL;
- if (0 == strcmp(method->type.type.data, "void")) {
- c->statements->Add(realCall);
-
- if (!oneway) {
- // report that there were no exceptions
- MethodCall* ex = new MethodCall(stubClass->transact_reply,
- "writeNoException", 0);
- c->statements->Add(ex);
- }
- } else {
- _result = new Variable(decl->returnType, "_result",
- decl->returnTypeDimension);
- c->statements->Add(new VariableDeclaration(_result, realCall));
-
- if (!oneway) {
- // report that there were no exceptions
- MethodCall* ex = new MethodCall(stubClass->transact_reply,
- "writeNoException", 0);
- c->statements->Add(ex);
- }
-
- // marshall the return value
- generate_write_to_parcel(decl->returnType, c->statements, _result,
- stubClass->transact_reply,
- Type::PARCELABLE_WRITE_RETURN_VALUE);
- }
-
- // out parameters
- i = 0;
- arg = method->args;
- while (arg != NULL) {
- Type* t = NAMES.Search(arg->type.type.data);
- Variable* v = stubArgs.Get(i++);
-
- if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
- generate_write_to_parcel(t, c->statements, v,
- stubClass->transact_reply,
- Type::PARCELABLE_WRITE_RETURN_VALUE);
- hasOutParams = true;
- }
-
- arg = arg->next;
- }
-
- // return true
- c->statements->Add(new ReturnStatement(TRUE_VALUE));
- stubClass->transact_switch->cases.push_back(c);
-
- // == the proxy method ===================================================
- Method* proxy = new Method;
- proxy->comment = gather_comments(method->comments_token->extra);
- proxy->modifiers = PUBLIC | OVERRIDE;
- proxy->returnType = NAMES.Search(method->type.type.data);
- proxy->returnTypeDimension = method->type.dimension;
- proxy->name = method->name.data;
- proxy->statements = new StatementBlock;
- arg = method->args;
- while (arg != NULL) {
- proxy->parameters.push_back(new Variable(
- NAMES.Search(arg->type.type.data), arg->name.data,
- arg->type.dimension));
- arg = arg->next;
- }
- proxy->exceptions.push_back(REMOTE_EXCEPTION_TYPE);
- proxyClass->elements.push_back(proxy);
-
- // the parcels
- Variable* _data = new Variable(PARCEL_TYPE, "_data");
- proxy->statements->Add(new VariableDeclaration(_data,
- new MethodCall(PARCEL_TYPE, "obtain")));
- Variable* _reply = NULL;
- if (!oneway) {
- _reply = new Variable(PARCEL_TYPE, "_reply");
- proxy->statements->Add(new VariableDeclaration(_reply,
- new MethodCall(PARCEL_TYPE, "obtain")));
- }
-
- // the return value
- _result = NULL;
- if (0 != strcmp(method->type.type.data, "void")) {
- _result = new Variable(proxy->returnType, "_result",
- method->type.dimension);
- proxy->statements->Add(new VariableDeclaration(_result));
- }
-
- // try and finally
- TryStatement* tryStatement = new TryStatement();
- proxy->statements->Add(tryStatement);
- FinallyStatement* finallyStatement = new FinallyStatement();
- proxy->statements->Add(finallyStatement);
-
- // the interface identifier token: the DESCRIPTOR constant, marshalled as a string
- tryStatement->statements->Add(new MethodCall(_data, "writeInterfaceToken",
- 1, new LiteralExpression("DESCRIPTOR")));
-
- // the parameters
- arg = method->args;
- while (arg != NULL) {
- Type* t = NAMES.Search(arg->type.type.data);
- Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
- int dir = convert_direction(arg->direction.data);
- if (dir == OUT_PARAMETER && arg->type.dimension != 0) {
- IfStatement* checklen = new IfStatement();
- checklen->expression = new Comparison(v, "==", NULL_VALUE);
- checklen->statements->Add(new MethodCall(_data, "writeInt", 1,
- new LiteralExpression("-1")));
- checklen->elseif = new IfStatement();
- checklen->elseif->statements->Add(new MethodCall(_data, "writeInt",
- 1, new FieldVariable(v, "length")));
- tryStatement->statements->Add(checklen);
- }
- else if (dir & IN_PARAMETER) {
- generate_write_to_parcel(t, tryStatement->statements, v, _data, 0);
- }
- arg = arg->next;
- }
-
- // the transact call
- MethodCall* call = new MethodCall(proxyClass->mRemote, "transact", 4,
- new LiteralExpression("Stub." + transactCodeName),
- _data, _reply ? _reply : NULL_VALUE,
- new LiteralExpression(
- oneway ? "android.os.IBinder.FLAG_ONEWAY" : "0"));
- tryStatement->statements->Add(call);
-
- // throw back exceptions.
- if (_reply) {
- MethodCall* ex = new MethodCall(_reply, "readException", 0);
- tryStatement->statements->Add(ex);
- }
-
- // returning and cleanup
- if (_reply != NULL) {
- if (_result != NULL) {
- generate_create_from_parcel(proxy->returnType,
- tryStatement->statements, _result, _reply, &cl);
- }
-
- // the out/inout parameters
- arg = method->args;
- while (arg != NULL) {
- Type* t = NAMES.Search(arg->type.type.data);
- Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
- if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
- generate_read_from_parcel(t, tryStatement->statements,
- v, _reply, &cl);
- }
- arg = arg->next;
- }
-
- finallyStatement->statements->Add(new MethodCall(_reply, "recycle"));
- }
- finallyStatement->statements->Add(new MethodCall(_data, "recycle"));
-
- if (_result != NULL) {
- proxy->statements->Add(new ReturnStatement(_result));
- }
-}
-
-static void
-generate_interface_descriptors(StubClass* stub, ProxyClass* proxy)
-{
- // the interface descriptor transaction handler
- Case* c = new Case("INTERFACE_TRANSACTION");
- c->statements->Add(new MethodCall(stub->transact_reply, "writeString",
- 1, new LiteralExpression("DESCRIPTOR")));
- c->statements->Add(new ReturnStatement(TRUE_VALUE));
- stub->transact_switch->cases.push_back(c);
-
- // and the proxy-side method returning the descriptor directly
- Method* getDesc = new Method;
- getDesc->modifiers = PUBLIC;
- getDesc->returnType = STRING_TYPE;
- getDesc->returnTypeDimension = 0;
- getDesc->name = "getInterfaceDescriptor";
- getDesc->statements = new StatementBlock;
- getDesc->statements->Add(new ReturnStatement(new LiteralExpression("DESCRIPTOR")));
- proxy->elements.push_back(getDesc);
-}
-
-Class*
-generate_binder_interface_class(const interface_type* iface)
-{
- InterfaceType* interfaceType = static_cast<InterfaceType*>(
- NAMES.Find(iface->package, iface->name.data));
-
- // the interface class
- Class* interface = new Class;
- interface->comment = gather_comments(iface->comments_token->extra);
- interface->modifiers = PUBLIC;
- interface->what = Class::INTERFACE;
- interface->type = interfaceType;
- interface->interfaces.push_back(IINTERFACE_TYPE);
-
- // the stub inner class
- StubClass* stub = new StubClass(
- NAMES.Find(iface->package, append(iface->name.data, ".Stub").c_str()),
- interfaceType);
- interface->elements.push_back(stub);
-
- // the proxy inner class
- ProxyClass* proxy = new ProxyClass(
- NAMES.Find(iface->package,
- append(iface->name.data, ".Stub.Proxy").c_str()),
- interfaceType);
- stub->elements.push_back(proxy);
-
- // stub and proxy support for getInterfaceDescriptor()
- generate_interface_descriptors(stub, proxy);
-
- // all the declared methods of the interface
- int index = 0;
- interface_item_type* item = iface->interface_items;
- while (item != NULL) {
- if (item->item_type == METHOD_TYPE) {
- method_type * method_item = (method_type*) item;
- generate_method(method_item, interface, stub, proxy, method_item->assigned_id);
- }
- item = item->next;
- index++;
- }
-
- return interface;
-}
-
diff --git a/tools/aidl/macros.h b/tools/aidl/macros.h
deleted file mode 100644
index 67b8076404a4..000000000000
--- a/tools/aidl/macros.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef AIDL_MACROS_H_
-#define AIDL_MACROS_H_
-
-#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
- TypeName(const TypeName&); \
- void operator=(const TypeName&)
-
-#endif // AIDL_MACROS_H_
diff --git a/tools/aidl/main.cpp b/tools/aidl/main.cpp
deleted file mode 100644
index 7cc2198bb5df..000000000000
--- a/tools/aidl/main.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
-#include "aidl.h"
-#include "options.h"
-
-#include <stdio.h>
-
-int
-main(int argc, const char **argv)
-{
- Options options;
- int result = parse_options(argc, argv, &options);
- if (result) {
- return result;
- }
-
- switch (options.task) {
- case COMPILE_AIDL:
- return compile_aidl(options);
- case PREPROCESS_AIDL:
- return preprocess_aidl(options);
- }
- fprintf(stderr, "aidl: internal error\n");
- return 1;
-}
diff --git a/tools/aidl/options.cpp b/tools/aidl/options.cpp
deleted file mode 100644
index 52b0972a89ee..000000000000
--- a/tools/aidl/options.cpp
+++ /dev/null
@@ -1,150 +0,0 @@
-
-#include "options.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-static int
-usage()
-{
- fprintf(stderr,
- "usage: aidl OPTIONS INPUT [OUTPUT]\n"
- " aidl --preprocess OUTPUT INPUT...\n"
- "\n"
- "OPTIONS:\n"
- " -I<DIR> search path for import statements.\n"
- " -d<FILE> generate dependency file.\n"
- " -a generate dependency file next to the output file with the name based on the input file.\n"
- " -p<FILE> file created by --preprocess to import.\n"
- " -o<FOLDER> base output folder for generated files.\n"
- " -b fail when trying to compile a parcelable.\n"
- "\n"
- "INPUT:\n"
- " An aidl interface file.\n"
- "\n"
- "OUTPUT:\n"
- " The generated interface files.\n"
- " If omitted and the -o option is not used, the input filename is used, with the .aidl extension changed to a .java extension.\n"
- " If the -o option is used, the generated files will be placed in the base output folder, under their package folder\n"
- );
- return 1;
-}
-
-int
-parse_options(int argc, const char* const* argv, Options *options)
-{
- int i = 1;
-
- if (argc >= 2 && 0 == strcmp(argv[1], "--preprocess")) {
- if (argc < 4) {
- return usage();
- }
- options->outputFileName = argv[2];
- for (int i=3; i<argc; i++) {
- options->filesToPreprocess.push_back(argv[i]);
- }
- options->task = PREPROCESS_AIDL;
- return 0;
- }
-
- // OPTIONS
- while (i < argc) {
- const char* s = argv[i];
- int len = strlen(s);
- if (s[0] == '-') {
- if (len > 1) {
- // -I<system-import-path>
- if (s[1] == 'I') {
- if (len > 2) {
- options->importPaths.push_back(s+2);
- } else {
- fprintf(stderr, "-I option (%d) requires a path.\n", i);
- return usage();
- }
- }
- else if (s[1] == 'd') {
- if (len > 2) {
- options->depFileName = s+2;
- } else {
- fprintf(stderr, "-d option (%d) requires a file.\n", i);
- return usage();
- }
- }
- else if (s[1] == 'a') {
- options->autoDepFile = true;
- }
- else if (s[1] == 'p') {
- if (len > 2) {
- options->preprocessedFiles.push_back(s+2);
- } else {
- fprintf(stderr, "-p option (%d) requires a file.\n", i);
- return usage();
- }
- }
- else if (s[1] == 'o') {
- if (len > 2) {
- options->outputBaseFolder = s+2;
- } else {
- fprintf(stderr, "-o option (%d) requires a path.\n", i);
- return usage();
- }
- }
- else if (len == 2 && s[1] == 'b') {
- options->failOnParcelable = true;
- }
- else {
- // s[1] is not known
- fprintf(stderr, "unknown option (%d): %s\n", i, s);
- return usage();
- }
- } else {
- // len <= 1
- fprintf(stderr, "unknown option (%d): %s\n", i, s);
- return usage();
- }
- } else {
- // s[0] != '-'
- break;
- }
- i++;
- }
-
- // INPUT
- if (i < argc) {
- options->inputFileName = argv[i];
- i++;
- } else {
- fprintf(stderr, "INPUT required\n");
- return usage();
- }
-
- // OUTPUT
- if (i < argc) {
- options->outputFileName = argv[i];
- i++;
- } else if (options->outputBaseFolder.length() == 0) {
- // copy input into output and change the extension from .aidl to .java
- options->outputFileName = options->inputFileName;
- string::size_type pos = options->outputFileName.size()-5;
- if (options->outputFileName.compare(pos, 5, ".aidl") == 0) { // 5 = strlen(".aidl")
- options->outputFileName.replace(pos, 5, ".java"); // 5 = strlen(".aidl")
- } else {
- fprintf(stderr, "INPUT is not an .aidl file.\n");
- return usage();
- }
- }
-
- // anything remaining?
- if (i != argc) {
- fprintf(stderr, "unknown option%s:", (i==argc-1?(const char*)"":(const char*)"s"));
- for (; i<argc-1; i++) {
- fprintf(stderr, " %s", argv[i]);
- }
- fprintf(stderr, "\n");
- return usage();
- }
-
- return 0;
-}
-
diff --git a/tools/aidl/options.h b/tools/aidl/options.h
deleted file mode 100644
index 4e95e1162836..000000000000
--- a/tools/aidl/options.h
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef AIDL_OPTIONS_H_
-#define AIDL_OPTIONS_H_
-
-#include <string.h>
-#include <string>
-#include <vector>
-
-using namespace std;
-
-enum {
- COMPILE_AIDL,
- PREPROCESS_AIDL
-};
-
-// This struct is the parsed version of the command line options
-struct Options
-{
- int task{COMPILE_AIDL};
- bool failOnParcelable{false};
- vector<string> importPaths;
- vector<string> preprocessedFiles;
- string inputFileName;
- string outputFileName;
- string outputBaseFolder;
- string depFileName;
- bool autoDepFile{false};
-
- vector<string> filesToPreprocess;
-};
-
-// takes the inputs from the command line and fills in the Options struct
-// Returns 0 on success, and nonzero on failure.
-// It also prints the usage statement on failure.
-int parse_options(int argc, const char* const* argv, Options *options);
-
-#endif // AIDL_OPTIONS_H_
diff --git a/tools/aidl/options_unittest.cpp b/tools/aidl/options_unittest.cpp
deleted file mode 100644
index fec7f877d02a..000000000000
--- a/tools/aidl/options_unittest.cpp
+++ /dev/null
@@ -1,54 +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.
- */
-
-#include <string>
-#include <vector>
-
-#include <gtest/gtest.h>
-
-#include "options.h"
-
-using std::vector;
-using std::string;
-
-const char kPreprocessCommandOutputFile[] = "output_file_name";
-const char kPreprocessCommandInput1[] = "input1";
-const char kPreprocessCommandInput2[] = "input2";
-const char kPreprocessCommandInput3[] = "input3";
-const char* kPreprocessCommand[] = {
- "aidl", "--preprocess",
- kPreprocessCommandOutputFile,
- kPreprocessCommandInput1,
- kPreprocessCommandInput2,
- kPreprocessCommandInput3,
-};
-
-TEST(OptionsTests, ParsesPreprocess) {
- Options options;
- const int argc = sizeof(kPreprocessCommand) / sizeof(*kPreprocessCommand);
- EXPECT_EQ(parse_options(argc, kPreprocessCommand, &options), 0);
- EXPECT_EQ(options.task, PREPROCESS_AIDL);
- EXPECT_EQ(options.failOnParcelable, false);
- EXPECT_EQ(options.importPaths.size(), 0u);
- EXPECT_EQ(options.preprocessedFiles.size(), 0u);
- EXPECT_EQ(options.inputFileName, string{""});
- EXPECT_EQ(options.outputFileName, string{kPreprocessCommandOutputFile});
- EXPECT_EQ(options.autoDepFile, false);
- const vector<string> expected_input{kPreprocessCommandInput1,
- kPreprocessCommandInput2,
- kPreprocessCommandInput3};
- EXPECT_EQ(options.filesToPreprocess, expected_input);
-}
diff --git a/tools/aidl/search_path.cpp b/tools/aidl/search_path.cpp
deleted file mode 100644
index 029e216b0abd..000000000000
--- a/tools/aidl/search_path.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-#include <unistd.h>
-#include "search_path.h"
-#include "options.h"
-#include "os.h"
-#include <string.h>
-
-#ifdef _WIN32
-#include <io.h>
-#endif
-
-static vector<string> g_importPaths;
-
-void
-set_import_paths(const vector<string>& importPaths)
-{
- g_importPaths = importPaths;
-}
-
-char*
-find_import_file(const char* given)
-{
- string expected = given;
-
- int N = expected.length();
- for (int i=0; i<N; i++) {
- char c = expected[i];
- if (c == '.') {
- expected[i] = OS_PATH_SEPARATOR;
- }
- }
- expected += ".aidl";
-
- vector<string>& paths = g_importPaths;
- for (vector<string>::iterator it=paths.begin(); it!=paths.end(); it++) {
- string f = *it;
- if (f.size() == 0) {
- f = ".";
- f += OS_PATH_SEPARATOR;
- }
- else if (f[f.size()-1] != OS_PATH_SEPARATOR) {
- f += OS_PATH_SEPARATOR;
- }
- f.append(expected);
-
-#ifdef _WIN32
- /* check that the file exists and is not write-only */
- if (0 == _access(f.c_str(), 0) && /* mode 0=exist */
- 0 == _access(f.c_str(), 4) ) { /* mode 4=readable */
-#else
- if (0 == access(f.c_str(), R_OK)) {
-#endif
- return strdup(f.c_str());
- }
- }
-
- return NULL;
-}
-
diff --git a/tools/aidl/search_path.h b/tools/aidl/search_path.h
deleted file mode 100644
index 4fec257557de..000000000000
--- a/tools/aidl/search_path.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef AIDL_SEARCH_PATH_H_
-#define AIDL_SEARCH_PATH_H_
-
-#include <stdio.h>
-
-#if __cplusplus
-#include <vector>
-#include <string>
-using namespace std;
-extern "C" {
-#endif
-
-// returns a FILE* and the char* for the file that it found
-// given is the class name we're looking for
-char* find_import_file(const char* given);
-
-#if __cplusplus
-}; // extern "C"
-void set_import_paths(const vector<string>& importPaths);
-#endif
-
-#endif // AIDL_SEARCH_PATH_H_
diff --git a/tools/aidl/test_main.cpp b/tools/aidl/test_main.cpp
deleted file mode 100644
index 4d820af774e1..000000000000
--- a/tools/aidl/test_main.cpp
+++ /dev/null
@@ -1,6 +0,0 @@
-#include <gtest/gtest.h>
-
-int main(int argc, char **argv) {
- ::testing::InitGoogleTest(&argc, argv);
- return RUN_ALL_TESTS();
-}
diff --git a/tools/aidl/tests/end_to_end_tests.cpp b/tools/aidl/tests/end_to_end_tests.cpp
deleted file mode 100644
index 54ca60319ce1..000000000000
--- a/tools/aidl/tests/end_to_end_tests.cpp
+++ /dev/null
@@ -1,165 +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.
- */
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include <base/logging.h>
-#include <base/files/file_path.h>
-#include <base/files/file_util.h>
-#include <gtest/gtest.h>
-
-#include "aidl.h"
-#include "options.h"
-#include "tests/test_data.h"
-
-using base::FilePath;
-using std::string;
-using std::unique_ptr;
-using std::vector;
-
-using namespace aidl::test_data;
-
-namespace {
-
-const char kDiffTemplate[] = "diff %s %s";
-const char kStubInterfaceTemplate[] = "package %s;\ninterface %s { }";
-const char kStubParcelableTemplate[] = "package %s;\nparcelable %s;";
-
-FilePath GetPathForPackageClass(const char* package_class,
- const char* extension) {
- string rel_path{package_class};
- for (char& c : rel_path) {
- if (c == '.') {
- c = FilePath::kSeparators[0];
- }
- }
- rel_path += extension;
- return FilePath(rel_path);
-}
-
-void SplitPackageClass(const string& package_class,
- FilePath* rel_path,
- string* package,
- string* class_name) {
- *package = string{package_class, 0, package_class.rfind('.')};
- *class_name = string{package_class, package_class.rfind('.') + 1};
- *rel_path = GetPathForPackageClass(package_class.c_str(), ".aidl");
-}
-
-} // namespace
-
-class EndToEndTest : public ::testing::Test {
- protected:
- virtual void SetUp() {
- ASSERT_TRUE(base::CreateNewTempDirectory(
- string{"end_to_end_testsyyyy"}, &tmpDir_));
- inputDir_ = tmpDir_.Append("input");
- outputDir_ = tmpDir_.Append("output");
- ASSERT_TRUE(base::CreateDirectory(inputDir_));
- ASSERT_TRUE(base::CreateDirectory(outputDir_));
- }
-
- virtual void TearDown() {
- ASSERT_TRUE(DeleteFile(tmpDir_, true))
- << "Failed to remove temp directory: " << tmpDir_.value();
- }
-
- FilePath CreateInputFile(const FilePath& relative_path,
- const char contents[],
- int size) {
- const FilePath created_file = inputDir_.Append(relative_path);
- EXPECT_TRUE(base::CreateDirectory(created_file.DirName()));
- EXPECT_TRUE(base::WriteFile(created_file, contents, size));
- return created_file;
- }
-
- void CreateStubAidlFile(const string& package_class,
- const char* file_template) {
- string package, class_name;
- FilePath rel_path;
- SplitPackageClass(package_class, &rel_path, &package, &class_name);
- const size_t buf_len =
- strlen(file_template) + package.length() + class_name.length() + 1;
- unique_ptr<char[]> contents(new char[buf_len]);
- const int written = snprintf(contents.get(), buf_len, file_template,
- package.c_str(), class_name.c_str());
- EXPECT_GT(written, 0);
- CreateInputFile(rel_path, contents.get(), written);
- }
-
- void WriteStubAidls(const char** parcelables, const char** interfaces) {
- while (*parcelables) {
- CreateStubAidlFile(string{*parcelables}, kStubParcelableTemplate);
- ++parcelables;
- }
- while (*interfaces) {
- CreateStubAidlFile(string{*interfaces}, kStubInterfaceTemplate);
- ++interfaces;
- }
- }
-
- void CheckFileContents(const FilePath& rel_path,
- const string& expected_content) {
- string actual_contents;
- FilePath actual_path = outputDir_.Append(rel_path);
- if (!ReadFileToString(actual_path, &actual_contents)) {
- FAIL() << "Failed to read expected output file: " << rel_path.value();
- }
- // Generated .java files mention the "original" file as part of their
- // comment header. Thus we look for expected_content being a substring.
- if (actual_contents.find(expected_content) == string::npos) {
- // When the match fails, display a diff of what's wrong. This greatly
- // aids in debugging.
- FilePath expected_path;
- EXPECT_TRUE(CreateTemporaryFileInDir(tmpDir_, &expected_path));
- base::WriteFile(expected_path, expected_content.c_str(),
- expected_content.length());
- const size_t buf_len =
- strlen(kDiffTemplate) + actual_path.value().length() +
- expected_path.value().length() + 1;
- unique_ptr<char[]> diff_cmd(new char[buf_len]);
- EXPECT_GT(snprintf(diff_cmd.get(), buf_len, kDiffTemplate,
- expected_path.value().c_str(),
- actual_path.value().c_str()), 0);
- system(diff_cmd.get());
- FAIL() << "Actual contents of " << rel_path.value()
- << " did not match expected content";
- }
- }
-
- FilePath tmpDir_;
- FilePath inputDir_;
- FilePath outputDir_;
-};
-
-TEST_F(EndToEndTest, IExampleInterface) {
- Options options;
- options.failOnParcelable = true;
- options.importPaths.push_back(inputDir_.value());
- options.inputFileName =
- CreateInputFile(GetPathForPackageClass(kIExampleInterfaceClass, ".aidl"),
- kIExampleInterfaceContents,
- strlen(kIExampleInterfaceContents)).value();
- options.autoDepFile = true;
- options.outputBaseFolder = outputDir_.value();
- WriteStubAidls(kIExampleInterfaceParcelables, kIExampleInterfaceInterfaces);
- EXPECT_EQ(compile_aidl(options), 0);
- CheckFileContents(GetPathForPackageClass(kIExampleInterfaceClass, ".java"),
- kIExampleInterfaceJava);
- // We'd like to check the depends file, but it mentions unique file paths.
-}
diff --git a/tools/aidl/tests/example_interface_test_data.cpp b/tools/aidl/tests/example_interface_test_data.cpp
deleted file mode 100644
index b17a800a6ac4..000000000000
--- a/tools/aidl/tests/example_interface_test_data.cpp
+++ /dev/null
@@ -1,404 +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.
- */
-
-#include "tests/test_data.h"
-
-namespace aidl {
-namespace test_data {
-
-const char kIExampleInterfaceClass[] = "android.test.IExampleInterface";
-
-const char* kIExampleInterfaceParcelables[] = {
- "android.foo.ExampleParcelable",
- "android.test.ExampleParcelable2",
- nullptr,
-};
-
-const char* kIExampleInterfaceInterfaces[] = {
- "android.bar.IAuxInterface",
- "android.test.IAuxInterface2",
- nullptr,
-};
-
-const char kIExampleInterfaceContents[] = R"(
-package android.test;
-
-import android.foo.ExampleParcelable;
-import android.test.ExampleParcelable2;
-import android.bar.IAuxInterface;
-import android.test.IAuxInterface2;
-
-interface IExampleInterface {
- boolean isEnabled();
- int getState();
- String getAddress();
-
- ExampleParcelable[] getParcelables();
-
- boolean setScanMode(int mode, int duration);
-
- void registerBinder(IAuxInterface foo);
- IExampleInterface getRecursiveBinder();
-
- int takesAnInterface(in IAuxInterface2 arg);
- int takesAParcelable(in ExampleParcelable2 arg);
-}
-)";
-
-const char kIExampleInterfaceDeps[] =
-R"(/tmp/.org.chromium.Chromium.Cdq7YZ/output/android/test/IExampleInterface.java: \
- /tmp/.org.chromium.Chromium.Cdq7YZ/input/android/test/IExampleInterface.aidl \
- /tmp/.org.chromium.Chromium.Cdq7YZ/input/android/foo/ExampleParcelable.aidl \
- /tmp/.org.chromium.Chromium.Cdq7YZ/input/android/test/ExampleParcelable2.aidl \
- /tmp/.org.chromium.Chromium.Cdq7YZ/input/android/bar/IAuxInterface.aidl \
- /tmp/.org.chromium.Chromium.Cdq7YZ/input/android/test/IAuxInterface2.aidl
-
-/tmp/.org.chromium.Chromium.Cdq7YZ/input/android/test/IExampleInterface.aidl :
-/tmp/.org.chromium.Chromium.Cdq7YZ/input/android/foo/ExampleParcelable.aidl :
-/tmp/.org.chromium.Chromium.Cdq7YZ/input/android/test/ExampleParcelable2.aidl :
-/tmp/.org.chromium.Chromium.Cdq7YZ/input/android/bar/IAuxInterface.aidl :
-/tmp/.org.chromium.Chromium.Cdq7YZ/input/android/test/IAuxInterface2.aidl :)";
-
-const char kIExampleInterfaceJava[] =
-R"(package android.test;
-public interface IExampleInterface extends android.os.IInterface
-{
-/** Local-side IPC implementation stub class. */
-public static abstract class Stub extends android.os.Binder implements android.test.IExampleInterface
-{
-private static final java.lang.String DESCRIPTOR = "android.test.IExampleInterface";
-/** Construct the stub at attach it to the interface. */
-public Stub()
-{
-this.attachInterface(this, DESCRIPTOR);
-}
-/**
- * Cast an IBinder object into an android.test.IExampleInterface interface,
- * generating a proxy if needed.
- */
-public static android.test.IExampleInterface asInterface(android.os.IBinder obj)
-{
-if ((obj==null)) {
-return null;
-}
-android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
-if (((iin!=null)&&(iin instanceof android.test.IExampleInterface))) {
-return ((android.test.IExampleInterface)iin);
-}
-return new android.test.IExampleInterface.Stub.Proxy(obj);
-}
-@Override public android.os.IBinder asBinder()
-{
-return this;
-}
-@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
-{
-switch (code)
-{
-case INTERFACE_TRANSACTION:
-{
-reply.writeString(DESCRIPTOR);
-return true;
-}
-case TRANSACTION_isEnabled:
-{
-data.enforceInterface(DESCRIPTOR);
-boolean _result = this.isEnabled();
-reply.writeNoException();
-reply.writeInt(((_result)?(1):(0)));
-return true;
-}
-case TRANSACTION_getState:
-{
-data.enforceInterface(DESCRIPTOR);
-int _result = this.getState();
-reply.writeNoException();
-reply.writeInt(_result);
-return true;
-}
-case TRANSACTION_getAddress:
-{
-data.enforceInterface(DESCRIPTOR);
-java.lang.String _result = this.getAddress();
-reply.writeNoException();
-reply.writeString(_result);
-return true;
-}
-case TRANSACTION_getParcelables:
-{
-data.enforceInterface(DESCRIPTOR);
-android.foo.ExampleParcelable[] _result = this.getParcelables();
-reply.writeNoException();
-reply.writeTypedArray(_result, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
-return true;
-}
-case TRANSACTION_setScanMode:
-{
-data.enforceInterface(DESCRIPTOR);
-int _arg0;
-_arg0 = data.readInt();
-int _arg1;
-_arg1 = data.readInt();
-boolean _result = this.setScanMode(_arg0, _arg1);
-reply.writeNoException();
-reply.writeInt(((_result)?(1):(0)));
-return true;
-}
-case TRANSACTION_registerBinder:
-{
-data.enforceInterface(DESCRIPTOR);
-android.bar.IAuxInterface _arg0;
-_arg0 = android.bar.IAuxInterface.Stub.asInterface(data.readStrongBinder());
-this.registerBinder(_arg0);
-reply.writeNoException();
-return true;
-}
-case TRANSACTION_getRecursiveBinder:
-{
-data.enforceInterface(DESCRIPTOR);
-android.test.IExampleInterface _result = this.getRecursiveBinder();
-reply.writeNoException();
-reply.writeStrongBinder((((_result!=null))?(_result.asBinder()):(null)));
-return true;
-}
-case TRANSACTION_takesAnInterface:
-{
-data.enforceInterface(DESCRIPTOR);
-android.test.IAuxInterface2 _arg0;
-_arg0 = android.test.IAuxInterface2.Stub.asInterface(data.readStrongBinder());
-int _result = this.takesAnInterface(_arg0);
-reply.writeNoException();
-reply.writeInt(_result);
-return true;
-}
-case TRANSACTION_takesAParcelable:
-{
-data.enforceInterface(DESCRIPTOR);
-android.test.ExampleParcelable2 _arg0;
-if ((0!=data.readInt())) {
-_arg0 = android.test.ExampleParcelable2.CREATOR.createFromParcel(data);
-}
-else {
-_arg0 = null;
-}
-int _result = this.takesAParcelable(_arg0);
-reply.writeNoException();
-reply.writeInt(_result);
-return true;
-}
-}
-return super.onTransact(code, data, reply, flags);
-}
-private static class Proxy implements android.test.IExampleInterface
-{
-private android.os.IBinder mRemote;
-Proxy(android.os.IBinder remote)
-{
-mRemote = remote;
-}
-@Override public android.os.IBinder asBinder()
-{
-return mRemote;
-}
-public java.lang.String getInterfaceDescriptor()
-{
-return DESCRIPTOR;
-}
-@Override public boolean isEnabled() throws android.os.RemoteException
-{
-android.os.Parcel _data = android.os.Parcel.obtain();
-android.os.Parcel _reply = android.os.Parcel.obtain();
-boolean _result;
-try {
-_data.writeInterfaceToken(DESCRIPTOR);
-mRemote.transact(Stub.TRANSACTION_isEnabled, _data, _reply, 0);
-_reply.readException();
-_result = (0!=_reply.readInt());
-}
-finally {
-_reply.recycle();
-_data.recycle();
-}
-return _result;
-}
-@Override public int getState() throws android.os.RemoteException
-{
-android.os.Parcel _data = android.os.Parcel.obtain();
-android.os.Parcel _reply = android.os.Parcel.obtain();
-int _result;
-try {
-_data.writeInterfaceToken(DESCRIPTOR);
-mRemote.transact(Stub.TRANSACTION_getState, _data, _reply, 0);
-_reply.readException();
-_result = _reply.readInt();
-}
-finally {
-_reply.recycle();
-_data.recycle();
-}
-return _result;
-}
-@Override public java.lang.String getAddress() throws android.os.RemoteException
-{
-android.os.Parcel _data = android.os.Parcel.obtain();
-android.os.Parcel _reply = android.os.Parcel.obtain();
-java.lang.String _result;
-try {
-_data.writeInterfaceToken(DESCRIPTOR);
-mRemote.transact(Stub.TRANSACTION_getAddress, _data, _reply, 0);
-_reply.readException();
-_result = _reply.readString();
-}
-finally {
-_reply.recycle();
-_data.recycle();
-}
-return _result;
-}
-@Override public android.foo.ExampleParcelable[] getParcelables() throws android.os.RemoteException
-{
-android.os.Parcel _data = android.os.Parcel.obtain();
-android.os.Parcel _reply = android.os.Parcel.obtain();
-android.foo.ExampleParcelable[] _result;
-try {
-_data.writeInterfaceToken(DESCRIPTOR);
-mRemote.transact(Stub.TRANSACTION_getParcelables, _data, _reply, 0);
-_reply.readException();
-_result = _reply.createTypedArray(android.foo.ExampleParcelable.CREATOR);
-}
-finally {
-_reply.recycle();
-_data.recycle();
-}
-return _result;
-}
-@Override public boolean setScanMode(int mode, int duration) throws android.os.RemoteException
-{
-android.os.Parcel _data = android.os.Parcel.obtain();
-android.os.Parcel _reply = android.os.Parcel.obtain();
-boolean _result;
-try {
-_data.writeInterfaceToken(DESCRIPTOR);
-_data.writeInt(mode);
-_data.writeInt(duration);
-mRemote.transact(Stub.TRANSACTION_setScanMode, _data, _reply, 0);
-_reply.readException();
-_result = (0!=_reply.readInt());
-}
-finally {
-_reply.recycle();
-_data.recycle();
-}
-return _result;
-}
-@Override public void registerBinder(android.bar.IAuxInterface foo) throws android.os.RemoteException
-{
-android.os.Parcel _data = android.os.Parcel.obtain();
-android.os.Parcel _reply = android.os.Parcel.obtain();
-try {
-_data.writeInterfaceToken(DESCRIPTOR);
-_data.writeStrongBinder((((foo!=null))?(foo.asBinder()):(null)));
-mRemote.transact(Stub.TRANSACTION_registerBinder, _data, _reply, 0);
-_reply.readException();
-}
-finally {
-_reply.recycle();
-_data.recycle();
-}
-}
-@Override public android.test.IExampleInterface getRecursiveBinder() throws android.os.RemoteException
-{
-android.os.Parcel _data = android.os.Parcel.obtain();
-android.os.Parcel _reply = android.os.Parcel.obtain();
-android.test.IExampleInterface _result;
-try {
-_data.writeInterfaceToken(DESCRIPTOR);
-mRemote.transact(Stub.TRANSACTION_getRecursiveBinder, _data, _reply, 0);
-_reply.readException();
-_result = android.test.IExampleInterface.Stub.asInterface(_reply.readStrongBinder());
-}
-finally {
-_reply.recycle();
-_data.recycle();
-}
-return _result;
-}
-@Override public int takesAnInterface(android.test.IAuxInterface2 arg) throws android.os.RemoteException
-{
-android.os.Parcel _data = android.os.Parcel.obtain();
-android.os.Parcel _reply = android.os.Parcel.obtain();
-int _result;
-try {
-_data.writeInterfaceToken(DESCRIPTOR);
-_data.writeStrongBinder((((arg!=null))?(arg.asBinder()):(null)));
-mRemote.transact(Stub.TRANSACTION_takesAnInterface, _data, _reply, 0);
-_reply.readException();
-_result = _reply.readInt();
-}
-finally {
-_reply.recycle();
-_data.recycle();
-}
-return _result;
-}
-@Override public int takesAParcelable(android.test.ExampleParcelable2 arg) throws android.os.RemoteException
-{
-android.os.Parcel _data = android.os.Parcel.obtain();
-android.os.Parcel _reply = android.os.Parcel.obtain();
-int _result;
-try {
-_data.writeInterfaceToken(DESCRIPTOR);
-if ((arg!=null)) {
-_data.writeInt(1);
-arg.writeToParcel(_data, 0);
-}
-else {
-_data.writeInt(0);
-}
-mRemote.transact(Stub.TRANSACTION_takesAParcelable, _data, _reply, 0);
-_reply.readException();
-_result = _reply.readInt();
-}
-finally {
-_reply.recycle();
-_data.recycle();
-}
-return _result;
-}
-}
-static final int TRANSACTION_isEnabled = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
-static final int TRANSACTION_getState = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
-static final int TRANSACTION_getAddress = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
-static final int TRANSACTION_getParcelables = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);
-static final int TRANSACTION_setScanMode = (android.os.IBinder.FIRST_CALL_TRANSACTION + 4);
-static final int TRANSACTION_registerBinder = (android.os.IBinder.FIRST_CALL_TRANSACTION + 5);
-static final int TRANSACTION_getRecursiveBinder = (android.os.IBinder.FIRST_CALL_TRANSACTION + 6);
-static final int TRANSACTION_takesAnInterface = (android.os.IBinder.FIRST_CALL_TRANSACTION + 7);
-static final int TRANSACTION_takesAParcelable = (android.os.IBinder.FIRST_CALL_TRANSACTION + 8);
-}
-public boolean isEnabled() throws android.os.RemoteException;
-public int getState() throws android.os.RemoteException;
-public java.lang.String getAddress() throws android.os.RemoteException;
-public android.foo.ExampleParcelable[] getParcelables() throws android.os.RemoteException;
-public boolean setScanMode(int mode, int duration) throws android.os.RemoteException;
-public void registerBinder(android.bar.IAuxInterface foo) throws android.os.RemoteException;
-public android.test.IExampleInterface getRecursiveBinder() throws android.os.RemoteException;
-public int takesAnInterface(android.test.IAuxInterface2 arg) throws android.os.RemoteException;
-public int takesAParcelable(android.test.ExampleParcelable2 arg) throws android.os.RemoteException;
-})";
-
-} // namespace test_data
-} // namespace aidl
diff --git a/tools/aidl/tests/test_data.h b/tools/aidl/tests/test_data.h
deleted file mode 100644
index cd8887ff3d13..000000000000
--- a/tools/aidl/tests/test_data.h
+++ /dev/null
@@ -1,33 +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.
- */
-
-#ifndef AIDL_TESTS_TEST_DATA_H_
-#define AIDL_TESTS_TEST_DATA_H_
-
-namespace aidl {
-namespace test_data {
-
-extern const char kIExampleInterfaceClass[];
-extern const char kIExampleInterfaceContents[];
-extern const char* kIExampleInterfaceParcelables[];
-extern const char* kIExampleInterfaceInterfaces[];
-
-extern const char kIExampleInterfaceDeps[];
-extern const char kIExampleInterfaceJava[];
-
-} // namespace test_data
-} // namespace aidl
-#endif // AIDL_TESTS_TEST_DATA_H_
diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java b/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java
index 163fbcb7f900..3b7bf8549181 100644
--- a/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java
+++ b/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java
@@ -48,9 +48,6 @@ import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.Iterator;
-/**
- *
- */
public final class BridgeResources extends Resources {
private BridgeContext mContext;
@@ -278,7 +275,7 @@ public final class BridgeResources extends Resources {
* always Strings. The ideal signature for the method should be &lt;T super String&gt;, but java
* generics don't support it.
*/
- private <T extends CharSequence> T[] fillValues(ArrayResourceValue resValue, T[] values) {
+ <T extends CharSequence> T[] fillValues(ArrayResourceValue resValue, T[] values) {
int i = 0;
for (Iterator<String> iterator = resValue.iterator(); iterator.hasNext(); i++) {
@SuppressWarnings("unchecked")
diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
index 6a6109047573..31dd3d943769 100644
--- a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
+++ b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
@@ -16,6 +16,7 @@
package android.content.res;
+import com.android.ide.common.rendering.api.ArrayResourceValue;
import com.android.ide.common.rendering.api.AttrResourceValue;
import com.android.ide.common.rendering.api.LayoutLog;
import com.android.ide.common.rendering.api.RenderResources;
@@ -33,6 +34,7 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import android.annotation.Nullable;
+import android.content.res.Resources.NotFoundException;
import android.content.res.Resources.Theme;
import android.graphics.drawable.Drawable;
import android.util.DisplayMetrics;
@@ -740,12 +742,20 @@ public final class BridgeTypedArray extends TypedArray {
*/
@Override
public CharSequence[] getTextArray(int index) {
- String value = getString(index);
- if (value != null) {
- return new CharSequence[] { value };
+ if (!hasValue(index)) {
+ return null;
}
-
- return null;
+ ResourceValue resVal = mResourceData[index];
+ if (resVal instanceof ArrayResourceValue) {
+ ArrayResourceValue array = (ArrayResourceValue) resVal;
+ int count = array.getElementCount();
+ return count >= 0 ? mBridgeResources.fillValues(array, new CharSequence[count]) : null;
+ }
+ int id = getResourceId(index, 0);
+ String resIdMessage = id > 0 ? " (resource id 0x" + Integer.toHexString(id) + ')' : "";
+ throw new NotFoundException(
+ String.format("%1$s in %2$s%3$s is not a valid array resource.",
+ resVal.getValue(), mNames[index], resIdMessage));
}
@Override
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 93ecfa57950b..0da6bb62006c 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -76,7 +76,7 @@ public class IWindowManagerImpl implements IWindowManager {
@Override
public void addAppToken(int arg0, IApplicationToken arg1, int arg2, int arg3, int arg4,
boolean arg5, boolean arg6, int arg7, int arg8, boolean arg9, boolean arg10,
- Rect arg11, Configuration arg12) throws RemoteException {
+ Rect arg11, Configuration arg12, boolean arg13) throws RemoteException {
// TODO Auto-generated method stub
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
index 9824fa1b4702..299790765e39 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
@@ -148,7 +148,7 @@ public final class BridgeWindowSession implements IWindowSession {
}
@Override
- public boolean startMoving(IWindow window, float startX, float startY)
+ public boolean startMovingTask(IWindow window, float startX, float startY)
throws RemoteException {
// pass for now
return false;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index 24e1ce7db7ec..2a4f58381aee 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -1050,11 +1050,7 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
}
if (scrollPos != 0) {
view.scrollBy(0, scrollPos);
- } else {
- view.scrollBy(0, scrollPos);
}
- } else {
- view.scrollBy(0, scrollPos);
}
if (!(view instanceof ViewGroup)) {
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 0d95b38feb46..23be8e076174 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -23,6 +23,7 @@ import android.net.wifi.WifiInfo;
import android.net.wifi.ScanSettings;
import android.net.wifi.WifiChannel;
import android.net.wifi.ScanResult;
+import android.net.wifi.ScanInfo;
import android.net.wifi.WifiConnectionStatistics;
import android.net.wifi.WifiActivityEnergyInfo;
import android.net.Network;
@@ -70,6 +71,10 @@ interface IWifiManager
void disconnect();
+ List<ScanInfo> getScanInfos(String callingPackage);
+
+ void setOsuSelection(int osuID);
+
void reconnect();
void reassociate();
diff --git a/tools/aidl/os.h b/wifi/java/android/net/wifi/ScanInfo.aidl
index 752ed4777b0c..18ae5088146f 100644
--- a/tools/aidl/os.h
+++ b/wifi/java/android/net/wifi/ScanInfo.aidl
@@ -1,5 +1,5 @@
-/*
- * Copyright 2015, 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.
@@ -14,13 +14,6 @@
* limitations under the License.
*/
-#ifndef AIDL_OS_H_
-#define AIDL_OS_H_
+package android.net.wifi;
-#if defined(_WIN32)
-#define OS_PATH_SEPARATOR '\\'
-#else
-#define OS_PATH_SEPARATOR '/'
-#endif
-
-#endif // AIDL_OS_H_
+parcelable ScanInfo;
diff --git a/wifi/java/android/net/wifi/ScanInfo.java b/wifi/java/android/net/wifi/ScanInfo.java
new file mode 100644
index 000000000000..39186fa7a38a
--- /dev/null
+++ b/wifi/java/android/net/wifi/ScanInfo.java
@@ -0,0 +1,189 @@
+package android.net.wifi;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+public class ScanInfo implements Parcelable {
+ private final ScanResult mScanResult;
+
+ private final long mBSSID; // The BSSID of the best AP with an SSID matching the OSU
+ private final int mRSSI; // RSSI of the AP with BSSID
+ private final String mSSID; // The SSID to connect to for an OSU connection.
+ private final String mName;
+ private final String mServiceDescription;
+ private final String mIconType;
+ private final byte[] mIconData;
+ private final int mOSUIdentity;
+
+ public ScanInfo(ScanResult scanResult) {
+ mScanResult = scanResult;
+
+ mBSSID = -1;
+ mRSSI = -1;
+ mSSID = null;
+ mName = null;
+ mServiceDescription = null;
+ mIconType = null;
+ mIconData = null;
+ mOSUIdentity = -1;
+ }
+
+ public ScanInfo(long BSSID, int rssi, String SSID, String name, String serviceDescription,
+ String iconType, byte[] iconData, int OSUIdentity) {
+ mBSSID = BSSID;
+ mRSSI = rssi;
+ mSSID = SSID;
+ mName = name;
+ mServiceDescription = serviceDescription;
+ mIconType = iconType;
+ mIconData = iconData;
+ mOSUIdentity = OSUIdentity;
+
+ mScanResult = null;
+ }
+
+ /**
+ * Get the scan result of this ScanInfo.
+ * @return The ScanResult, if this ScanInfo contains a one. If the ScanInfo contains
+ * OSU information getScanResult will return null.
+ */
+ public ScanResult getScanResult() {
+ return mScanResult;
+ }
+
+ /**
+ * OSU only: The BSSID of the AP who advertises the OSU SSID. This value is not guaranteed to
+ * be correct; In the somewhat unlikely case that multiple APs advertise OSU SSIDs that matches
+ * an OSU information element returned through ANQP and one of those is not related to an OSU
+ * there is a (slight) risk that the BSSID is for a "spoof" OSU.
+ * The matching algorithm that produces the ScanInfo objects makes a best effort to get the
+ * matching right though and since it is (a) fair to assume that the OSU SSID resides on the
+ * same AP as the one advertising the OSU information, and (b) BSSIDs for multi-SSID APs are
+ * typically adjacent to each other, matching will prefer the BSSID closest to the advertising
+ * APs BSSID if multiple SSIDs match.
+ * @return The BSSID.
+ */
+ public long getBssid() {
+ return mBSSID;
+ }
+
+ /**
+ * OSU only.
+ * @return The signal level of the AP associated with the BSSID from getBSSID.
+ */
+ public int getRssi() {
+ return mRSSI;
+ }
+
+ /**
+ * OSU only.
+ * @return The SSID of the AP to which to associate to establish an OSU connection.
+ */
+ public String getSsid() {
+ return mSSID;
+ }
+
+ /**
+ * OSU only.
+ * @return The name of the Service Provider of the OSU.
+ */
+ public String getName() {
+ return mName;
+ }
+
+ /**
+ * OSU only.
+ * @return The service description of the OSU.
+ */
+ public String getServiceDescription() {
+ return mServiceDescription;
+ }
+
+ /**
+ * OSU only.
+ * Get the type of icon that icon data represents, e.g. JPG, PNG etc. This field is formatted
+ * using standard MIME encodings per RFC-4288 and IANA MIME media types.
+ * @return The icon type in icon data.
+ */
+ public String getIconType() {
+ return mIconType;
+ }
+
+ /**
+ * OSU only.
+ * @return The binary data of the icon.
+ */
+ public byte[] getIconData() {
+ return mIconData;
+ }
+
+ /**
+ * OSU only.
+ * @return a unique identity for the OSU. This value is generated by the framework and should
+ * be used to uniquely identify a specific OSU. Please note that values may be reused after
+ * a very long time-span (in any normal scenario, likely years) and implementations should make
+ * sure to not rely on any long term persisted values.
+ */
+ public int getOsuIdentity() {
+ return mOSUIdentity;
+ }
+
+ private static final int ScanResultMarker = 0;
+ private static final int OSUMarker = 1;
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public static final Creator<ScanInfo> CREATOR =
+ new Creator<ScanInfo>() {
+ @Override
+ public ScanInfo createFromParcel(Parcel source) {
+ int marker = source.readInt();
+ if (marker == ScanResultMarker) {
+ return new ScanInfo(ScanResult.CREATOR.createFromParcel(source));
+ }
+ else if (marker == OSUMarker) {
+ return new ScanInfo(
+ source.readLong(),
+ source.readInt(),
+ source.readString(),
+ source.readString(),
+ source.readString(),
+ source.readString(),
+ source.createByteArray(),
+ source.readInt()
+ );
+ }
+ else {
+ throw new RuntimeException("Bad ScanInfo data");
+ }
+ }
+
+ @Override
+ public ScanInfo[] newArray(int size) {
+ return new ScanInfo[0];
+ }
+ };
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ if (mScanResult != null) {
+ dest.writeInt(ScanResultMarker);
+ mScanResult.writeToParcel(dest, flags);
+ return;
+ }
+
+ dest.writeInt(OSUMarker);
+ dest.writeLong(mBSSID);
+ dest.writeInt(mRSSI);
+ dest.writeString(mSSID);
+ dest.writeString(mName);
+ dest.writeString(mServiceDescription);
+ dest.writeString(mIconType);
+ dest.writeByteArray(mIconData);
+ dest.writeInt(mOSUIdentity);
+ }
+}
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index cf88df42f8d3..ff8d6d4d09aa 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1315,6 +1315,30 @@ public class WifiManager {
}
/**
+ * An augmented version of getScanResults that returns ScanResults as well as OSU information
+ * wrapped in ScanInfo objects.
+ * @return
+ */
+ public List<ScanInfo> getScanInfos() {
+ try {
+ return mService.getScanInfos(mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Notify the OSU framework about the currently selected OSU.
+ * @param osuID The OSU ID from ScanInfo.getOsuIdentity()
+ */
+ public void setOsuSelection(int osuID) {
+ try {
+ mService.setOsuSelection(osuID);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
* Check if scanning is always available.
*
* If this return {@code true}, apps can issue {@link #startScan} and fetch scan results