summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/sidecar/SettingsSidecarImpl.java6
-rw-r--r--libs/WindowManager/Shell/Android.bp4
-rw-r--r--libs/WindowManager/Shell/res/anim/tv_pip_controls_focus_gain_animation.xml20
-rw-r--r--libs/WindowManager/Shell/res/anim/tv_pip_controls_focus_loss_animation.xml20
-rw-r--r--libs/WindowManager/Shell/res/anim/tv_pip_menu_fade_in_animation.xml20
-rw-r--r--libs/WindowManager/Shell/res/anim/tv_pip_menu_fade_out_animation.xml20
-rw-r--r--libs/WindowManager/Shell/res/drawable/floating_dismiss_gradient.xml25
-rw-r--r--libs/WindowManager/Shell/res/drawable/floating_dismiss_gradient_transition.xml20
-rw-r--r--libs/WindowManager/Shell/res/drawable/pip_expand.xml28
-rw-r--r--libs/WindowManager/Shell/res/drawable/pip_ic_close_white.xml25
-rw-r--r--libs/WindowManager/Shell/res/drawable/pip_ic_fullscreen_white.xml25
-rw-r--r--libs/WindowManager/Shell/res/drawable/pip_ic_pause_white.xml26
-rw-r--r--libs/WindowManager/Shell/res/drawable/pip_ic_play_arrow_white.xml26
-rw-r--r--libs/WindowManager/Shell/res/drawable/pip_ic_settings.xml28
-rw-r--r--libs/WindowManager/Shell/res/drawable/pip_icon.xml25
-rw-r--r--libs/WindowManager/Shell/res/drawable/pip_resize_handle.xml29
-rw-r--r--libs/WindowManager/Shell/res/drawable/tv_pip_button_focused.xml18
-rw-r--r--libs/WindowManager/Shell/res/layout/pip_menu_action.xml23
-rw-r--r--libs/WindowManager/Shell/res/layout/pip_menu_activity.xml100
-rw-r--r--libs/WindowManager/Shell/res/layout/tv_pip_control_button.xml50
-rw-r--r--libs/WindowManager/Shell/res/layout/tv_pip_controls.xml43
-rw-r--r--libs/WindowManager/Shell/res/layout/tv_pip_custom_control.xml21
-rw-r--r--libs/WindowManager/Shell/res/layout/tv_pip_menu.xml31
-rw-r--r--libs/WindowManager/Shell/res/values-tvdpi/dimen.xml22
-rw-r--r--libs/WindowManager/Shell/res/values/config.xml42
-rw-r--r--libs/WindowManager/Shell/res/values/dimen.xml59
-rw-r--r--libs/WindowManager/Shell/res/values/ids.xml19
-rw-r--r--libs/WindowManager/Shell/res/values/strings.xml56
-rw-r--r--libs/WindowManager/Shell/res/values/strings_tv.xml34
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayChangeController.java109
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java273
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java521
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java511
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java393
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/TransactionPool.java50
-rw-r--r--libs/WindowManager/Shell/tests/Android.bp3
-rw-r--r--libs/WindowManager/Shell/tests/src/com/android/wm/shell/WindowManagerShellTest.java (renamed from libs/WindowManager/Shell/tests/src/com/android/wm/shell/tests/WindowManagerShellTest.java)6
-rw-r--r--libs/WindowManager/Shell/tests/src/com/android/wm/shell/common/DisplayLayoutTest.java140
-rw-r--r--libs/androidfw/Android.bp1
-rw-r--r--libs/androidfw/BackupHelpers.cpp2
-rw-r--r--libs/androidfw/include/androidfw/BackupHelpers.h2
-rw-r--r--libs/androidfw/include/androidfw/ResourceTypes.h4
-rw-r--r--libs/androidfw/tests/BackupHelpers_test.cpp63
-rw-r--r--libs/hwui/Android.bp54
-rw-r--r--libs/hwui/AnimationContext.h16
-rw-r--r--libs/hwui/Animator.h54
-rw-r--r--libs/hwui/AnimatorManager.h2
-rw-r--r--libs/hwui/AutoBackendTextureRelease.cpp10
-rw-r--r--libs/hwui/AutoBackendTextureRelease.h9
-rw-r--r--libs/hwui/CanvasTransform.cpp1
-rw-r--r--libs/hwui/ColorMode.h34
-rw-r--r--libs/hwui/DamageAccumulator.h2
-rw-r--r--libs/hwui/DeferredLayerUpdater.cpp2
-rw-r--r--libs/hwui/DeferredLayerUpdater.h18
-rw-r--r--libs/hwui/DeviceInfo.cpp129
-rw-r--r--libs/hwui/DeviceInfo.h53
-rw-r--r--libs/hwui/FrameInfo.h2
-rw-r--r--libs/hwui/HardwareBitmapUploader.cpp98
-rw-r--r--libs/hwui/HardwareBitmapUploader.h2
-rw-r--r--libs/hwui/Interpolator.h22
-rw-r--r--libs/hwui/Matrix.h2
-rw-r--r--libs/hwui/PathParser.h10
-rw-r--r--libs/hwui/Properties.cpp1
-rw-r--r--libs/hwui/Properties.h16
-rw-r--r--libs/hwui/PropertyValuesAnimatorSet.h2
-rw-r--r--libs/hwui/PropertyValuesHolder.h18
-rw-r--r--libs/hwui/Readback.cpp7
-rw-r--r--libs/hwui/RecordingCanvas.cpp66
-rw-r--r--libs/hwui/RecordingCanvas.h20
-rw-r--r--libs/hwui/RenderNode.h22
-rw-r--r--libs/hwui/RenderProperties.h4
-rw-r--r--libs/hwui/RootRenderNode.h19
-rw-r--r--libs/hwui/SkiaCanvas.cpp6
-rw-r--r--libs/hwui/SkiaCanvas.h6
-rw-r--r--libs/hwui/VectorDrawable.h14
-rw-r--r--libs/hwui/apex/java/android/graphics/ColorMatrix.java288
-rw-r--r--libs/hwui/apex/jni_runtime.cpp19
-rw-r--r--libs/hwui/api/current.txt23
-rw-r--r--libs/hwui/api/module-lib-current.txt1
-rw-r--r--libs/hwui/api/module-lib-removed.txt1
-rw-r--r--libs/hwui/api/removed.txt1
-rw-r--r--libs/hwui/api/system-current.txt1
-rw-r--r--libs/hwui/api/system-removed.txt1
-rw-r--r--libs/hwui/hwui/AnimatedImageDrawable.h2
-rw-r--r--libs/hwui/hwui/Bitmap.cpp40
-rw-r--r--libs/hwui/hwui/Bitmap.h16
-rw-r--r--libs/hwui/hwui/Canvas.h6
-rw-r--r--libs/hwui/hwui/MinikinSkia.cpp16
-rw-r--r--libs/hwui/hwui/MinikinUtils.h14
-rw-r--r--libs/hwui/hwui/Paint.h2
-rwxr-xr-xlibs/hwui/jni/Bitmap.cpp447
-rw-r--r--libs/hwui/jni/BitmapFactory.cpp11
-rw-r--r--libs/hwui/jni/BitmapRegionDecoder.cpp82
-rw-r--r--libs/hwui/jni/CreateJavaOutputStreamAdaptor.cpp21
-rw-r--r--libs/hwui/jni/CreateJavaOutputStreamAdaptor.h8
-rw-r--r--libs/hwui/jni/FontFamily.cpp12
-rw-r--r--libs/hwui/jni/Graphics.cpp2
-rw-r--r--libs/hwui/jni/GraphicsJNI.h15
-rw-r--r--libs/hwui/jni/ImageDecoder.cpp5
-rw-r--r--libs/hwui/jni/Movie.cpp8
-rw-r--r--libs/hwui/jni/Shader.cpp9
-rw-r--r--libs/hwui/jni/Utils.cpp4
-rw-r--r--libs/hwui/jni/Utils.h5
-rw-r--r--libs/hwui/jni/android_graphics_DisplayListCanvas.cpp44
-rw-r--r--libs/hwui/jni/android_graphics_HardwareRenderer.cpp180
-rw-r--r--libs/hwui/jni/android_graphics_TextureLayer.cpp4
-rw-r--r--libs/hwui/jni/fonts/Font.cpp12
-rw-r--r--libs/hwui/libhwui.map.txt70
-rw-r--r--libs/hwui/pipeline/skia/FunctorDrawable.h31
-rw-r--r--libs/hwui/pipeline/skia/GLFunctorDrawable.cpp21
-rw-r--r--libs/hwui/pipeline/skia/GLFunctorDrawable.h2
-rw-r--r--libs/hwui/pipeline/skia/LayerDrawable.cpp10
-rw-r--r--libs/hwui/pipeline/skia/LayerDrawable.h8
-rw-r--r--libs/hwui/pipeline/skia/ShaderCache.h2
-rw-r--r--libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp2
-rw-r--r--libs/hwui/pipeline/skia/SkiaPipeline.cpp32
-rw-r--r--libs/hwui/pipeline/skia/SkiaPipeline.h4
-rw-r--r--libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp25
-rw-r--r--libs/hwui/pipeline/skia/SkiaRecordingCanvas.h5
-rw-r--r--libs/hwui/pipeline/skia/VkFunctorDrawable.cpp9
-rw-r--r--libs/hwui/pipeline/skia/VkFunctorDrawable.h1
-rw-r--r--libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp71
-rw-r--r--libs/hwui/pipeline/skia/VkInteropFunctorDrawable.h11
-rw-r--r--libs/hwui/renderthread/CacheManager.cpp7
-rw-r--r--libs/hwui/renderthread/CanvasContext.cpp11
-rw-r--r--libs/hwui/renderthread/CanvasContext.h8
-rw-r--r--libs/hwui/renderthread/EglManager.cpp116
-rw-r--r--libs/hwui/renderthread/EglManager.h5
-rw-r--r--libs/hwui/renderthread/IRenderPipeline.h11
-rw-r--r--libs/hwui/renderthread/ReliableSurface.cpp28
-rw-r--r--libs/hwui/renderthread/ReliableSurface.h4
-rw-r--r--libs/hwui/renderthread/RenderProxy.cpp18
-rw-r--r--libs/hwui/renderthread/RenderProxy.h107
-rw-r--r--libs/hwui/renderthread/RenderTask.h8
-rw-r--r--libs/hwui/renderthread/RenderThread.cpp6
-rw-r--r--libs/hwui/renderthread/RenderThread.h10
-rw-r--r--libs/hwui/renderthread/VulkanManager.cpp39
-rw-r--r--libs/hwui/renderthread/VulkanManager.h12
-rw-r--r--libs/hwui/renderthread/VulkanSurface.cpp10
-rw-r--r--libs/hwui/renderthread/VulkanSurface.h11
-rw-r--r--libs/hwui/service/GraphicsStatsService.cpp1
-rw-r--r--libs/hwui/service/GraphicsStatsService.h22
-rw-r--r--libs/hwui/tests/common/TestUtils.h24
-rw-r--r--libs/hwui/tests/common/scenes/MagnifierAnimation.cpp4
-rw-r--r--libs/hwui/tests/common/scenes/RecentsAnimation.cpp4
-rw-r--r--libs/hwui/tests/common/scenes/RectGridAnimation.cpp4
-rw-r--r--libs/hwui/tests/common/scenes/RoundRectClippingAnimation.cpp4
-rw-r--r--libs/hwui/tests/common/scenes/ShadowGrid2Animation.cpp4
-rw-r--r--libs/hwui/tests/common/scenes/ShadowGridAnimation.cpp4
-rw-r--r--libs/hwui/tests/common/scenes/ShadowShaderAnimation.cpp4
-rw-r--r--libs/hwui/tests/common/scenes/TvApp.cpp4
-rw-r--r--libs/hwui/tests/microbench/DisplayListCanvasBench.cpp4
-rwxr-xr-xlibs/hwui/tests/scripts/prep_generic.sh209
-rw-r--r--libs/hwui/tests/unit/CacheManagerTests.cpp6
-rw-r--r--libs/hwui/tests/unit/CanvasContextTests.cpp11
-rw-r--r--libs/hwui/tests/unit/FatalTestCanvas.h15
-rw-r--r--libs/hwui/tests/unit/RenderNodeDrawableTests.cpp24
-rw-r--r--libs/hwui/tests/unit/RenderNodeTests.cpp50
-rw-r--r--libs/hwui/tests/unit/SkiaDisplayListTests.cpp17
-rw-r--r--libs/hwui/utils/Blur.h4
-rw-r--r--libs/hwui/utils/Color.cpp61
-rw-r--r--libs/hwui/utils/Color.h16
-rw-r--r--libs/hwui/utils/MathUtils.h4
-rw-r--r--libs/hwui/utils/NdkUtils.cpp (renamed from libs/hwui/GlFunctorLifecycleListener.h)20
-rw-r--r--libs/hwui/utils/NdkUtils.h38
-rw-r--r--libs/hwui/utils/VectorDrawableUtils.h6
-rw-r--r--libs/usb/tests/AccessoryChat/AndroidManifest.xml20
167 files changed, 4919 insertions, 1344 deletions
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SettingsSidecarImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SettingsSidecarImpl.java
index 92e575804bbe..ca3a5112bc55 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SettingsSidecarImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SettingsSidecarImpl.java
@@ -192,7 +192,7 @@ class SettingsSidecarImpl extends StubSidecar {
Rect featureRect = new Rect(left, top, right, bottom);
rotateRectToDisplayRotation(featureRect, displayId);
transformToWindowSpaceRect(featureRect, windowToken);
- if (!featureRect.isEmpty()) {
+ if (isNotZero(featureRect)) {
SidecarDisplayFeature feature = new SidecarDisplayFeature();
feature.setRect(featureRect);
feature.setType(type);
@@ -207,6 +207,10 @@ class SettingsSidecarImpl extends StubSidecar {
return features;
}
+ private static boolean isNotZero(Rect rect) {
+ return rect.height() > 0 || rect.width() > 0;
+ }
+
@Override
protected void onListenersChanged() {
if (mSettingsObserver == null) {
diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp
index b8934dc8c583..843b17703676 100644
--- a/libs/WindowManager/Shell/Android.bp
+++ b/libs/WindowManager/Shell/Android.bp
@@ -22,8 +22,4 @@ android_library {
"res",
],
manifest: "AndroidManifest.xml",
-
- platform_apis: true,
- sdk_version: "current",
- min_sdk_version: "system_current",
}
diff --git a/libs/WindowManager/Shell/res/anim/tv_pip_controls_focus_gain_animation.xml b/libs/WindowManager/Shell/res/anim/tv_pip_controls_focus_gain_animation.xml
new file mode 100644
index 000000000000..29d9b257cc59
--- /dev/null
+++ b/libs/WindowManager/Shell/res/anim/tv_pip_controls_focus_gain_animation.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:propertyName="alpha"
+ android:valueTo="1"
+ android:interpolator="@android:interpolator/fast_out_slow_in"
+ android:duration="100" />
diff --git a/libs/WindowManager/Shell/res/anim/tv_pip_controls_focus_loss_animation.xml b/libs/WindowManager/Shell/res/anim/tv_pip_controls_focus_loss_animation.xml
new file mode 100644
index 000000000000..70f553b89657
--- /dev/null
+++ b/libs/WindowManager/Shell/res/anim/tv_pip_controls_focus_loss_animation.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:propertyName="alpha"
+ android:valueTo="0"
+ android:interpolator="@android:interpolator/fast_out_slow_in"
+ android:duration="100" />
diff --git a/libs/WindowManager/Shell/res/anim/tv_pip_menu_fade_in_animation.xml b/libs/WindowManager/Shell/res/anim/tv_pip_menu_fade_in_animation.xml
new file mode 100644
index 000000000000..29d9b257cc59
--- /dev/null
+++ b/libs/WindowManager/Shell/res/anim/tv_pip_menu_fade_in_animation.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:propertyName="alpha"
+ android:valueTo="1"
+ android:interpolator="@android:interpolator/fast_out_slow_in"
+ android:duration="100" />
diff --git a/libs/WindowManager/Shell/res/anim/tv_pip_menu_fade_out_animation.xml b/libs/WindowManager/Shell/res/anim/tv_pip_menu_fade_out_animation.xml
new file mode 100644
index 000000000000..70f553b89657
--- /dev/null
+++ b/libs/WindowManager/Shell/res/anim/tv_pip_menu_fade_out_animation.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:propertyName="alpha"
+ android:valueTo="0"
+ android:interpolator="@android:interpolator/fast_out_slow_in"
+ android:duration="100" />
diff --git a/libs/WindowManager/Shell/res/drawable/floating_dismiss_gradient.xml b/libs/WindowManager/Shell/res/drawable/floating_dismiss_gradient.xml
new file mode 100644
index 000000000000..8b3057d5841e
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/floating_dismiss_gradient.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <gradient
+ android:angle="270"
+ android:startColor="#00000000"
+ android:endColor="#77000000"
+ android:type="linear" />
+</shape> \ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/floating_dismiss_gradient_transition.xml b/libs/WindowManager/Shell/res/drawable/floating_dismiss_gradient_transition.xml
new file mode 100644
index 000000000000..772d0a5ea89b
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/floating_dismiss_gradient_transition.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<transition xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@android:color/transparent" />
+ <item android:drawable="@drawable/floating_dismiss_gradient" />
+</transition> \ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/pip_expand.xml b/libs/WindowManager/Shell/res/drawable/pip_expand.xml
new file mode 100644
index 000000000000..c99d81934aab
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/pip_expand.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="36dp"
+ android:height="36dp"
+ android:viewportWidth="36"
+ android:viewportHeight="36">
+
+ <path
+ android:pathData="M0 0h36v36H0z" />
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M10 21H7v8h8v-3h-5v-5zm-3-6h3v-5h5V7H7v8zm19 11h-5v3h8v-8h-3v5zM21
+7v3h5v5h3V7h-8z" />
+</vector> \ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/pip_ic_close_white.xml b/libs/WindowManager/Shell/res/drawable/pip_ic_close_white.xml
new file mode 100644
index 000000000000..bcc850a854de
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/pip_ic_close_white.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<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:pathData="M19.000000,6.400000l-1.400000,-1.400000 -5.600000,5.600000 -5.600000,-5.600000 -1.400000,1.400000 5.600000,5.600000 -5.600000,5.600000 1.400000,1.400000 5.600000,-5.600000 5.600000,5.600000 1.400000,-1.400000 -5.600000,-5.600000z"
+ android:fillColor="#FFFFFFFF"/>
+</vector>
diff --git a/libs/WindowManager/Shell/res/drawable/pip_ic_fullscreen_white.xml b/libs/WindowManager/Shell/res/drawable/pip_ic_fullscreen_white.xml
new file mode 100644
index 000000000000..56699dc04e10
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/pip_ic_fullscreen_white.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z" />
+</vector>
diff --git a/libs/WindowManager/Shell/res/drawable/pip_ic_pause_white.xml b/libs/WindowManager/Shell/res/drawable/pip_ic_pause_white.xml
new file mode 100644
index 000000000000..ef9b2d9c1c63
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/pip_ic_pause_white.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M6 19h4V5H6v14zm8-14v14h4V5h-4z" />
+</vector>
diff --git a/libs/WindowManager/Shell/res/drawable/pip_ic_play_arrow_white.xml b/libs/WindowManager/Shell/res/drawable/pip_ic_play_arrow_white.xml
new file mode 100644
index 000000000000..f12d2cbebc87
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/pip_ic_play_arrow_white.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M8 5v14l11-7z" />
+</vector>
diff --git a/libs/WindowManager/Shell/res/drawable/pip_ic_settings.xml b/libs/WindowManager/Shell/res/drawable/pip_ic_settings.xml
new file mode 100644
index 000000000000..b61e98ce2f9f
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/pip_ic_settings.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M13.85,22.25h-3.7c-0.74,0 -1.36,-0.54 -1.45,-1.27l-0.27,-1.89c-0.27,-0.14 -0.53,-0.29 -0.79,-0.46l-1.8,0.72c-0.7,0.26 -1.47,-0.03 -1.81,-0.65L2.2,15.53c-0.35,-0.66 -0.2,-1.44 0.36,-1.88l1.53,-1.19c-0.01,-0.15 -0.02,-0.3 -0.02,-0.46c0,-0.15 0.01,-0.31 0.02,-0.46l-1.52,-1.19C1.98,9.9 1.83,9.09 2.2,8.47l1.85,-3.19c0.34,-0.62 1.11,-0.9 1.79,-0.63l1.81,0.73c0.26,-0.17 0.52,-0.32 0.78,-0.46l0.27,-1.91c0.09,-0.7 0.71,-1.25 1.44,-1.25h3.7c0.74,0 1.36,0.54 1.45,1.27l0.27,1.89c0.27,0.14 0.53,0.29 0.79,0.46l1.8,-0.72c0.71,-0.26 1.48,0.03 1.82,0.65l1.84,3.18c0.36,0.66 0.2,1.44 -0.36,1.88l-1.52,1.19c0.01,0.15 0.02,0.3 0.02,0.46s-0.01,0.31 -0.02,0.46l1.52,1.19c0.56,0.45 0.72,1.23 0.37,1.86l-1.86,3.22c-0.34,0.62 -1.11,0.9 -1.8,0.63l-1.8,-0.72c-0.26,0.17 -0.52,0.32 -0.78,0.46l-0.27,1.91C15.21,21.71 14.59,22.25 13.85,22.25zM13.32,20.72c0,0.01 0,0.01 0,0.02L13.32,20.72zM10.68,20.7l0,0.02C10.69,20.72 10.69,20.71 10.68,20.7zM10.62,20.25h2.76l0.37,-2.55l0.53,-0.22c0.44,-0.18 0.88,-0.44 1.34,-0.78l0.45,-0.34l2.38,0.96l1.38,-2.4l-2.03,-1.58l0.07,-0.56c0.03,-0.26 0.06,-0.51 0.06,-0.78c0,-0.27 -0.03,-0.53 -0.06,-0.78l-0.07,-0.56l2.03,-1.58l-1.39,-2.4l-2.39,0.96l-0.45,-0.35c-0.42,-0.32 -0.87,-0.58 -1.33,-0.77L13.75,6.3l-0.37,-2.55h-2.76L10.25,6.3L9.72,6.51C9.28,6.7 8.84,6.95 8.38,7.3L7.93,7.63L5.55,6.68L4.16,9.07l2.03,1.58l-0.07,0.56C6.09,11.47 6.06,11.74 6.06,12c0,0.26 0.02,0.53 0.06,0.78l0.07,0.56l-2.03,1.58l1.38,2.4l2.39,-0.96l0.45,0.35c0.43,0.33 0.86,0.58 1.33,0.77l0.53,0.22L10.62,20.25zM18.22,17.72c0,0.01 -0.01,0.02 -0.01,0.03L18.22,17.72zM5.77,17.71l0.01,0.02C5.78,17.72 5.77,17.71 5.77,17.71zM3.93,9.47L3.93,9.47C3.93,9.47 3.93,9.47 3.93,9.47zM18.22,6.27c0,0.01 0.01,0.02 0.01,0.02L18.22,6.27zM5.79,6.25L5.78,6.27C5.78,6.27 5.79,6.26 5.79,6.25zM13.31,3.28c0,0.01 0,0.01 0,0.02L13.31,3.28zM10.69,3.26l0,0.02C10.69,3.27 10.69,3.27 10.69,3.26z"/>
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M12,12m-3.5,0a3.5,3.5 0,1 1,7 0a3.5,3.5 0,1 1,-7 0"/>
+</vector>
diff --git a/libs/WindowManager/Shell/res/drawable/pip_icon.xml b/libs/WindowManager/Shell/res/drawable/pip_icon.xml
new file mode 100644
index 000000000000..b19d907d1ff3
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/pip_icon.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="36dp"
+ android:height="36dp"
+ android:viewportWidth="25"
+ android:viewportHeight="25">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M19,7h-8v6h8L19,7zM21,3L3,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,1.98 2,1.98h18c1.1,0 2,-0.88 2,-1.98L23,5c0,-1.1 -0.9,-2 -2,-2zM21,19.01L3,19.01L3,4.98h18v14.03z"/>
+</vector> \ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/pip_resize_handle.xml b/libs/WindowManager/Shell/res/drawable/pip_resize_handle.xml
new file mode 100644
index 000000000000..4d1e080cf466
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/pip_resize_handle.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="12.0dp"
+ android:height="12.0dp"
+ android:viewportWidth="12"
+ android:viewportHeight="12">
+ <group
+ android:translateX="12"
+ android:rotation="90">
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M3.41421 0L2 1.41422L10.4853 9.8995L11.8995 8.48528L3.41421 0ZM2.41421 4.24268L1 5.65689L6.65685 11.3137L8.07107 9.89953L2.41421 4.24268Z" />
+ </group>
+</vector>
diff --git a/libs/WindowManager/Shell/res/drawable/tv_pip_button_focused.xml b/libs/WindowManager/Shell/res/drawable/tv_pip_button_focused.xml
new file mode 100644
index 000000000000..cce13035dba7
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/tv_pip_button_focused.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="#9AFFFFFF" android:radius="17dp" />
diff --git a/libs/WindowManager/Shell/res/layout/pip_menu_action.xml b/libs/WindowManager/Shell/res/layout/pip_menu_action.xml
new file mode 100644
index 000000000000..7a026ca63f50
--- /dev/null
+++ b/libs/WindowManager/Shell/res/layout/pip_menu_action.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<ImageButton
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="@dimen/pip_action_size"
+ android:layout_height="@dimen/pip_action_size"
+ android:padding="@dimen/pip_action_padding"
+ android:background="?android:selectableItemBackgroundBorderless"
+ android:forceHasOverlappingRendering="false" />
diff --git a/libs/WindowManager/Shell/res/layout/pip_menu_activity.xml b/libs/WindowManager/Shell/res/layout/pip_menu_activity.xml
new file mode 100644
index 000000000000..2e0a5e09e34f
--- /dev/null
+++ b/libs/WindowManager/Shell/res/layout/pip_menu_activity.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/background"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <!-- Menu layout -->
+ <FrameLayout
+ android:id="@+id/menu_container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:forceHasOverlappingRendering="false"
+ android:accessibilityTraversalAfter="@id/dismiss">
+
+ <!-- The margins for this container is calculated in the code depending on whether the
+ actions_container is visible. -->
+ <FrameLayout
+ android:id="@+id/expand_container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <ImageButton
+ android:id="@+id/expand_button"
+ android:layout_width="60dp"
+ android:layout_height="60dp"
+ android:layout_gravity="center"
+ android:contentDescription="@string/pip_phone_expand"
+ android:padding="10dp"
+ android:src="@drawable/pip_expand"
+ android:background="?android:selectableItemBackgroundBorderless" />
+ </FrameLayout>
+
+ <FrameLayout
+ android:id="@+id/actions_container"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/pip_action_size"
+ android:layout_gravity="bottom"
+ android:visibility="invisible">
+ <LinearLayout
+ android:id="@+id/actions_group"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_gravity="center_horizontal"
+ android:orientation="horizontal"
+ android:divider="@android:color/transparent"
+ android:showDividers="middle" />
+ </FrameLayout>
+ </FrameLayout>
+
+ <LinearLayout
+ android:id="@+id/top_end_container"
+ android:layout_gravity="top|end"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+ <ImageButton
+ android:id="@+id/settings"
+ android:layout_width="@dimen/pip_action_size"
+ android:layout_height="@dimen/pip_action_size"
+ android:padding="@dimen/pip_action_padding"
+ android:contentDescription="@string/pip_phone_settings"
+ android:src="@drawable/pip_ic_settings"
+ android:background="?android:selectableItemBackgroundBorderless" />
+
+ <ImageButton
+ android:id="@+id/dismiss"
+ android:layout_width="@dimen/pip_action_size"
+ android:layout_height="@dimen/pip_action_size"
+ android:padding="@dimen/pip_action_padding"
+ android:contentDescription="@string/pip_phone_close"
+ android:src="@drawable/pip_ic_close_white"
+ android:background="?android:selectableItemBackgroundBorderless" />
+ </LinearLayout>
+
+ <!--TODO (b/156917828): Add content description for a11y purposes?-->
+ <ImageButton
+ android:id="@+id/resize_handle"
+ android:layout_width="@dimen/pip_resize_handle_size"
+ android:layout_height="@dimen/pip_resize_handle_size"
+ android:layout_gravity="top|start"
+ android:layout_margin="@dimen/pip_resize_handle_margin"
+ android:padding="@dimen/pip_resize_handle_padding"
+ android:src="@drawable/pip_resize_handle"
+ android:background="?android:selectableItemBackgroundBorderless" />
+</FrameLayout>
diff --git a/libs/WindowManager/Shell/res/layout/tv_pip_control_button.xml b/libs/WindowManager/Shell/res/layout/tv_pip_control_button.xml
new file mode 100644
index 000000000000..72287c144bed
--- /dev/null
+++ b/libs/WindowManager/Shell/res/layout/tv_pip_control_button.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<!-- Layout for {@link com.android.systemui.pip.tv.PipControlButtonView}. -->
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <ImageView android:id="@+id/button"
+ android:layout_width="34dp"
+ android:layout_height="34dp"
+ android:layout_alignParentTop="true"
+ android:layout_centerHorizontal="true"
+ android:focusable="true"
+ android:src="@drawable/tv_pip_button_focused"
+ android:importantForAccessibility="yes" />
+
+ <ImageView android:id="@+id/icon"
+ android:layout_width="34dp"
+ android:layout_height="34dp"
+ android:layout_alignParentTop="true"
+ android:layout_centerHorizontal="true"
+ android:padding="5dp"
+ android:importantForAccessibility="no" />
+
+ <TextView android:id="@+id/desc"
+ android:layout_width="100dp"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/icon"
+ android:layout_centerHorizontal="true"
+ android:layout_marginTop="3dp"
+ android:gravity="center"
+ android:text="@string/pip_fullscreen"
+ android:alpha="0"
+ android:fontFamily="sans-serif"
+ android:textSize="12sp"
+ android:textColor="#EEEEEE"
+ android:importantForAccessibility="no" />
+</merge>
diff --git a/libs/WindowManager/Shell/res/layout/tv_pip_controls.xml b/libs/WindowManager/Shell/res/layout/tv_pip_controls.xml
new file mode 100644
index 000000000000..22e0452d620d
--- /dev/null
+++ b/libs/WindowManager/Shell/res/layout/tv_pip_controls.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<!-- Layout for {@link com.android.systemui.pip.tv.PipControlsView}. -->
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <com.android.systemui.pip.tv.PipControlButtonView
+ android:id="@+id/full_button"
+ android:layout_width="@dimen/picture_in_picture_button_width"
+ android:layout_height="wrap_content"
+ android:src="@drawable/pip_ic_fullscreen_white"
+ android:text="@string/pip_fullscreen" />
+
+ <com.android.systemui.pip.tv.PipControlButtonView
+ android:id="@+id/close_button"
+ android:layout_width="@dimen/picture_in_picture_button_width"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/picture_in_picture_button_start_margin"
+ android:src="@drawable/pip_ic_close_white"
+ android:text="@string/pip_close" />
+
+ <com.android.systemui.pip.tv.PipControlButtonView
+ android:id="@+id/play_pause_button"
+ android:layout_width="@dimen/picture_in_picture_button_width"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/picture_in_picture_button_start_margin"
+ android:src="@drawable/pip_ic_pause_white"
+ android:text="@string/pip_pause"
+ android:visibility="gone" />
+</merge>
diff --git a/libs/WindowManager/Shell/res/layout/tv_pip_custom_control.xml b/libs/WindowManager/Shell/res/layout/tv_pip_custom_control.xml
new file mode 100644
index 000000000000..e6cd1122ca77
--- /dev/null
+++ b/libs/WindowManager/Shell/res/layout/tv_pip_custom_control.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<com.android.systemui.pip.tv.PipControlButtonView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="@dimen/picture_in_picture_button_width"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/picture_in_picture_button_start_margin" />
diff --git a/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml b/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml
new file mode 100644
index 000000000000..a049787b40b9
--- /dev/null
+++ b/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal"
+ android:paddingTop="350dp"
+ android:background="#CC000000"
+ android:gravity="top|center_horizontal"
+ android:clipChildren="false">
+
+ <com.android.systemui.pip.tv.PipControlsView
+ android:id="@+id/pip_controls"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:alpha="0" />
+</LinearLayout>
diff --git a/libs/WindowManager/Shell/res/values-tvdpi/dimen.xml b/libs/WindowManager/Shell/res/values-tvdpi/dimen.xml
new file mode 100644
index 000000000000..7920fd237a08
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-tvdpi/dimen.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <!-- The dimensions to user for picture-in-picture action buttons. -->
+ <dimen name="picture_in_picture_button_width">100dp</dimen>
+ <dimen name="picture_in_picture_button_start_margin">-50dp</dimen>
+</resources>
+
diff --git a/libs/WindowManager/Shell/res/values/config.xml b/libs/WindowManager/Shell/res/values/config.xml
index c894eb0133b5..245c0725c2a8 100644
--- a/libs/WindowManager/Shell/res/values/config.xml
+++ b/libs/WindowManager/Shell/res/values/config.xml
@@ -1,21 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-/*
-** Copyright 2019, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
+ Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
<resources>
-</resources> \ No newline at end of file
+ <!-- Animation duration for resizing of PIP when entering/exiting. -->
+ <integer name="config_pipResizeAnimationDuration">425</integer>
+
+ <!-- Allow dragging the PIP to a location to close it -->
+ <bool name="config_pipEnableDismissDragToEdge">true</bool>
+
+ <!-- Allow PIP to resize to a slightly bigger state upon touch/showing the menu -->
+ <bool name="config_pipEnableResizeForMenu">true</bool>
+
+ <!-- Allow PIP to enable round corner, see also R.dimen.pip_corner_radius -->
+ <bool name="config_pipEnableRoundCorner">false</bool>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
new file mode 100644
index 000000000000..1c1217681b9f
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <dimen name="dismiss_circle_size">52dp</dimen>
+
+ <!-- The height of the gradient indicating the dismiss edge when moving a PIP. -->
+ <dimen name="floating_dismiss_gradient_height">250dp</dimen>
+
+ <!-- The padding around a PiP actions. -->
+ <dimen name="pip_action_padding">12dp</dimen>
+
+ <!-- The height of the PiP actions container in which the actions are vertically centered. -->
+ <dimen name="pip_action_size">48dp</dimen>
+
+ <!-- The padding between actions in the PiP in landscape Note that the PiP does not reflect
+ the configuration of the device, so we can't use -land resources. -->
+ <dimen name="pip_between_action_padding_land">8dp</dimen>
+
+ <!-- The buffer to use when calculating whether the pip is in an adjust zone. -->
+ <dimen name="pip_bottom_offset_buffer">1dp</dimen>
+
+ <!-- The corner radius for PiP window. -->
+ <dimen name="pip_corner_radius">8dp</dimen>
+
+ <!-- The bottom margin of the PIP drag to dismiss info text shown when moving a PIP. -->
+ <dimen name="pip_dismiss_text_bottom_margin">24dp</dimen>
+
+ <!-- The bottom margin of the expand container when there are actions.
+ Equal to pip_action_size - pip_action_padding. -->
+ <dimen name="pip_expand_container_edge_margin">30dp</dimen>
+
+ <!-- The shortest-edge size of the expanded PiP. -->
+ <dimen name="pip_expanded_shortest_edge_size">160dp</dimen>
+
+ <!-- The additional offset to apply to the IME animation to account for the input field. -->
+ <dimen name="pip_ime_offset">48dp</dimen>
+
+ <!-- The touchable/draggable edge size for PIP resize. -->
+ <dimen name="pip_resize_edge_size">48dp</dimen>
+
+ <!-- PIP Resize handle size, margin and padding. -->
+ <dimen name="pip_resize_handle_size">12dp</dimen>
+ <dimen name="pip_resize_handle_margin">4dp</dimen>
+ <dimen name="pip_resize_handle_padding">0dp</dimen>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values/ids.xml b/libs/WindowManager/Shell/res/values/ids.xml
new file mode 100644
index 000000000000..ed20398f309d
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values/ids.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <item type="id" name="action_pip_resize" />
+</resources>
diff --git a/libs/WindowManager/Shell/res/values/strings.xml b/libs/WindowManager/Shell/res/values/strings.xml
new file mode 100644
index 000000000000..6752b56fcdf3
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Label for PIP close button [CHAR LIMIT=NONE]-->
+ <string name="pip_phone_close">Close</string>
+
+ <!-- Making the PIP fullscreen [CHAR LIMIT=25] -->
+ <string name="pip_phone_expand">Expand</string>
+
+ <!-- Label for PIP settings button [CHAR LIMIT=NONE]-->
+ <string name="pip_phone_settings">Settings</string>
+
+ <!-- Title of menu shown over picture-in-picture. Used for accessibility. -->
+ <string name="pip_menu_title">Menu</string>
+
+ <!-- PiP BTW notification title. [CHAR LIMIT=50] -->
+ <string name="pip_notification_title"><xliff:g id="name" example="Google Maps">%s</xliff:g> is in picture-in-picture</string>
+
+ <!-- PiP BTW notification description. [CHAR LIMIT=NONE] -->
+ <string name="pip_notification_message">If you don\'t want <xliff:g id="name" example="Google Maps">%s</xliff:g> to use this feature, tap to open settings and turn it off.</string>
+
+ <!-- Button to play the current media on picture-in-picture (PIP) [CHAR LIMIT=30] -->
+ <string name="pip_play">Play</string>
+
+ <!-- Button to pause the current media on picture-in-picture (PIP) [CHAR LIMIT=30] -->
+ <string name="pip_pause">Pause</string>
+
+ <!-- Button to skip to the next media on picture-in-picture (PIP) [CHAR LIMIT=30] -->
+ <string name="pip_skip_to_next">Skip to next</string>
+
+ <!-- Button to skip to the prev media on picture-in-picture (PIP) [CHAR LIMIT=30] -->
+ <string name="pip_skip_to_prev">Skip to previous</string>
+
+ <!-- Accessibility action for resizing PIP [CHAR LIMIT=NONE] -->
+ <string name="accessibility_action_pip_resize">Resize</string>
+
+ <!-- TODO Deprecated. Label for PIP action to Minimize the PIP. DO NOT TRANSLATE [CHAR LIMIT=25] -->
+ <string name="pip_phone_minimize">Minimize</string>
+
+ <!-- TODO Deprecated. Label for PIP the drag to dismiss hint. DO NOT TRANSLATE [CHAR LIMIT=NONE]-->
+ <string name="pip_phone_dismiss_hint">Drag down to dismiss</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values/strings_tv.xml b/libs/WindowManager/Shell/res/values/strings_tv.xml
new file mode 100644
index 000000000000..2dfdcabaa931
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values/strings_tv.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Picture-in-Picture (PIP) notification -->
+ <!-- Title for the notification channel for TV PIP controls. [CHAR LIMIT=NONE] -->
+ <string name="notification_channel_tv_pip">Picture-in-Picture</string>
+
+ <!-- Title of the picture-in-picture (PIP) notification title
+ when the media doesn't have title [CHAR LIMIT=NONE] -->
+ <string name="pip_notification_unknown_title">(No title program)</string>
+
+ <!-- Picture-in-Picture (PIP) menu -->
+ <eat-comment />
+ <!-- Button to close picture-in-picture (PIP) in PIP menu [CHAR LIMIT=30] -->
+ <string name="pip_close">Close PIP</string>
+
+ <!-- Button to move picture-in-picture (PIP) screen to the fullscreen in PIP menu [CHAR LIMIT=30] -->
+ <string name="pip_fullscreen">Full screen</string>
+</resources>
+
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayChangeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayChangeController.java
new file mode 100644
index 000000000000..3263f79888d6
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayChangeController.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.common;
+
+import android.os.Handler;
+import android.os.RemoteException;
+import android.view.IDisplayWindowRotationCallback;
+import android.view.IDisplayWindowRotationController;
+import android.view.IWindowManager;
+import android.window.WindowContainerTransaction;
+
+import java.util.ArrayList;
+
+/**
+ * This module deals with display rotations coming from WM. When WM starts a rotation: after it has
+ * frozen the screen, it will call into this class. This will then call all registered local
+ * controllers and give them a chance to queue up task changes to be applied synchronously with that
+ * rotation.
+ */
+public class DisplayChangeController {
+
+ private final Handler mHandler;
+ private final IWindowManager mWmService;
+
+ private final ArrayList<OnDisplayChangingListener> mRotationListener =
+ new ArrayList<>();
+ private final ArrayList<OnDisplayChangingListener> mTmpListeners = new ArrayList<>();
+
+ private final IDisplayWindowRotationController mDisplayRotationController =
+ new IDisplayWindowRotationController.Stub() {
+ @Override
+ public void onRotateDisplay(int displayId, final int fromRotation,
+ final int toRotation, IDisplayWindowRotationCallback callback) {
+ mHandler.post(() -> {
+ WindowContainerTransaction t = new WindowContainerTransaction();
+ synchronized (mRotationListener) {
+ mTmpListeners.clear();
+ // Make a local copy in case the handlers add/remove themselves.
+ mTmpListeners.addAll(mRotationListener);
+ }
+ for (OnDisplayChangingListener c : mTmpListeners) {
+ c.onRotateDisplay(displayId, fromRotation, toRotation, t);
+ }
+ try {
+ callback.continueRotateDisplay(toRotation, t);
+ } catch (RemoteException e) {
+ }
+ });
+ }
+ };
+
+ public DisplayChangeController(Handler mainHandler, IWindowManager wmService) {
+ mHandler = mainHandler;
+ mWmService = wmService;
+ try {
+ mWmService.setDisplayWindowRotationController(mDisplayRotationController);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Unable to register rotation controller");
+ }
+ }
+
+ /**
+ * Adds a display rotation controller.
+ */
+ public void addRotationListener(OnDisplayChangingListener listener) {
+ synchronized (mRotationListener) {
+ mRotationListener.add(listener);
+ }
+ }
+
+ /**
+ * Removes a display rotation controller.
+ */
+ public void removeRotationListener(OnDisplayChangingListener listener) {
+ synchronized (mRotationListener) {
+ mRotationListener.remove(listener);
+ }
+ }
+
+ /**
+ * Give a listener a chance to queue up configuration changes to execute as part of a
+ * display rotation. The contents of {@link #onRotateDisplay} must run synchronously.
+ */
+ public interface OnDisplayChangingListener {
+ /**
+ * Called before the display is rotated. Contents of this method must run synchronously.
+ * @param displayId Id of display that is rotating.
+ * @param fromRotation starting rotation of the display.
+ * @param toRotation target rotation of the display (after rotating).
+ * @param t A task transaction to populate.
+ */
+ void onRotateDisplay(int displayId, int fromRotation, int toRotation,
+ WindowContainerTransaction t);
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java
new file mode 100644
index 000000000000..418973204add
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.common;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.hardware.display.DisplayManager;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.view.Display;
+import android.view.IDisplayWindowListener;
+import android.view.IWindowManager;
+
+import com.android.wm.shell.common.DisplayChangeController.OnDisplayChangingListener;
+
+import java.util.ArrayList;
+
+/**
+ * This module deals with display rotations coming from WM. When WM starts a rotation: after it has
+ * frozen the screen, it will call into this class. This will then call all registered local
+ * controllers and give them a chance to queue up task changes to be applied synchronously with that
+ * rotation.
+ */
+public class DisplayController {
+ private static final String TAG = "DisplayController";
+
+ private final Handler mHandler;
+ private final Context mContext;
+ private final IWindowManager mWmService;
+ private final DisplayChangeController mChangeController;
+
+ private final SparseArray<DisplayRecord> mDisplays = new SparseArray<>();
+ private final ArrayList<OnDisplaysChangedListener> mDisplayChangedListeners = new ArrayList<>();
+
+ /**
+ * Gets a display by id from DisplayManager.
+ */
+ public Display getDisplay(int displayId) {
+ final DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
+ return displayManager.getDisplay(displayId);
+ }
+
+ private final IDisplayWindowListener mDisplayContainerListener =
+ new IDisplayWindowListener.Stub() {
+ @Override
+ public void onDisplayAdded(int displayId) {
+ mHandler.post(() -> {
+ synchronized (mDisplays) {
+ if (mDisplays.get(displayId) != null) {
+ return;
+ }
+ Display display = getDisplay(displayId);
+ if (display == null) {
+ // It's likely that the display is private to some app and thus not
+ // accessible by system-ui.
+ return;
+ }
+ DisplayRecord record = new DisplayRecord();
+ record.mDisplayId = displayId;
+ record.mContext = (displayId == Display.DEFAULT_DISPLAY) ? mContext
+ : mContext.createDisplayContext(display);
+ record.mDisplayLayout = new DisplayLayout(record.mContext, display);
+ mDisplays.put(displayId, record);
+ for (int i = 0; i < mDisplayChangedListeners.size(); ++i) {
+ mDisplayChangedListeners.get(i).onDisplayAdded(displayId);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
+ mHandler.post(() -> {
+ synchronized (mDisplays) {
+ DisplayRecord dr = mDisplays.get(displayId);
+ if (dr == null) {
+ Slog.w(TAG, "Skipping Display Configuration change on non-added"
+ + " display.");
+ return;
+ }
+ Display display = getDisplay(displayId);
+ if (display == null) {
+ Slog.w(TAG, "Skipping Display Configuration change on invalid"
+ + " display. It may have been removed.");
+ return;
+ }
+ Context perDisplayContext = mContext;
+ if (displayId != Display.DEFAULT_DISPLAY) {
+ perDisplayContext = mContext.createDisplayContext(display);
+ }
+ dr.mContext = perDisplayContext.createConfigurationContext(newConfig);
+ dr.mDisplayLayout = new DisplayLayout(dr.mContext, display);
+ for (int i = 0; i < mDisplayChangedListeners.size(); ++i) {
+ mDisplayChangedListeners.get(i).onDisplayConfigurationChanged(
+ displayId, newConfig);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void onDisplayRemoved(int displayId) {
+ mHandler.post(() -> {
+ synchronized (mDisplays) {
+ if (mDisplays.get(displayId) == null) {
+ return;
+ }
+ for (int i = mDisplayChangedListeners.size() - 1; i >= 0; --i) {
+ mDisplayChangedListeners.get(i).onDisplayRemoved(displayId);
+ }
+ mDisplays.remove(displayId);
+ }
+ });
+ }
+
+ @Override
+ public void onFixedRotationStarted(int displayId, int newRotation) {
+ mHandler.post(() -> {
+ synchronized (mDisplays) {
+ if (mDisplays.get(displayId) == null || getDisplay(displayId) == null) {
+ Slog.w(TAG, "Skipping onFixedRotationStarted on unknown"
+ + " display, displayId=" + displayId);
+ return;
+ }
+ for (int i = mDisplayChangedListeners.size() - 1; i >= 0; --i) {
+ mDisplayChangedListeners.get(i).onFixedRotationStarted(
+ displayId, newRotation);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void onFixedRotationFinished(int displayId) {
+ mHandler.post(() -> {
+ synchronized (mDisplays) {
+ if (mDisplays.get(displayId) == null || getDisplay(displayId) == null) {
+ Slog.w(TAG, "Skipping onFixedRotationFinished on unknown"
+ + " display, displayId=" + displayId);
+ return;
+ }
+ for (int i = mDisplayChangedListeners.size() - 1; i >= 0; --i) {
+ mDisplayChangedListeners.get(i).onFixedRotationFinished(displayId);
+ }
+ }
+ });
+ }
+ };
+
+ public DisplayController(Context context, Handler handler,
+ IWindowManager wmService) {
+ mHandler = handler;
+ mContext = context;
+ mWmService = wmService;
+ mChangeController = new DisplayChangeController(mHandler, mWmService);
+ try {
+ mWmService.registerDisplayWindowListener(mDisplayContainerListener);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Unable to register hierarchy listener");
+ }
+ }
+
+ /**
+ * Gets the DisplayLayout associated with a display.
+ */
+ public @Nullable DisplayLayout getDisplayLayout(int displayId) {
+ final DisplayRecord r = mDisplays.get(displayId);
+ return r != null ? r.mDisplayLayout : null;
+ }
+
+ /**
+ * Gets a display-specific context for a display.
+ */
+ public @Nullable Context getDisplayContext(int displayId) {
+ final DisplayRecord r = mDisplays.get(displayId);
+ return r != null ? r.mContext : null;
+ }
+
+ /**
+ * Add a display window-container listener. It will get notified whenever a display's
+ * configuration changes or when displays are added/removed from the WM hierarchy.
+ */
+ public void addDisplayWindowListener(OnDisplaysChangedListener listener) {
+ synchronized (mDisplays) {
+ if (mDisplayChangedListeners.contains(listener)) {
+ return;
+ }
+ mDisplayChangedListeners.add(listener);
+ for (int i = 0; i < mDisplays.size(); ++i) {
+ listener.onDisplayAdded(mDisplays.keyAt(i));
+ }
+ }
+ }
+
+ /**
+ * Remove a display window-container listener.
+ */
+ public void removeDisplayWindowListener(OnDisplaysChangedListener listener) {
+ synchronized (mDisplays) {
+ mDisplayChangedListeners.remove(listener);
+ }
+ }
+
+ /**
+ * Adds a display rotation controller.
+ */
+ public void addDisplayChangingController(OnDisplayChangingListener controller) {
+ mChangeController.addRotationListener(controller);
+ }
+
+ /**
+ * Removes a display rotation controller.
+ */
+ public void removeDisplayChangingController(OnDisplayChangingListener controller) {
+ mChangeController.removeRotationListener(controller);
+ }
+
+ private static class DisplayRecord {
+ int mDisplayId;
+ Context mContext;
+ DisplayLayout mDisplayLayout;
+ }
+
+ /**
+ * Gets notified when a display is added/removed to the WM hierarchy and when a display's
+ * window-configuration changes.
+ *
+ * @see IDisplayWindowListener
+ */
+ public interface OnDisplaysChangedListener {
+ /**
+ * Called when a display has been added to the WM hierarchy.
+ */
+ default void onDisplayAdded(int displayId) {}
+
+ /**
+ * Called when a display's window-container configuration changes.
+ */
+ default void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {}
+
+ /**
+ * Called when a display is removed.
+ */
+ default void onDisplayRemoved(int displayId) {}
+
+ /**
+ * Called when fixed rotation on a display is started.
+ */
+ default void onFixedRotationStarted(int displayId, int newRotation) {}
+
+ /**
+ * Called when fixed rotation on a display is finished.
+ */
+ default void onFixedRotationFinished(int displayId) {}
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
new file mode 100644
index 000000000000..aeda2d923490
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
@@ -0,0 +1,521 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.common;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.annotation.IntDef;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.view.IDisplayWindowInsetsController;
+import android.view.IWindowManager;
+import android.view.InsetsSource;
+import android.view.InsetsSourceControl;
+import android.view.InsetsState;
+import android.view.Surface;
+import android.view.SurfaceControl;
+import android.view.WindowInsets;
+import android.view.animation.Interpolator;
+import android.view.animation.PathInterpolator;
+
+import com.android.internal.view.IInputMethodManager;
+
+import java.util.ArrayList;
+
+/**
+ * Manages IME control at the display-level. This occurs when IME comes up in multi-window mode.
+ */
+public class DisplayImeController implements DisplayController.OnDisplaysChangedListener {
+ private static final String TAG = "DisplayImeController";
+
+ private static final boolean DEBUG = false;
+
+ // NOTE: All these constants came from InsetsController.
+ public static final int ANIMATION_DURATION_SHOW_MS = 275;
+ public static final int ANIMATION_DURATION_HIDE_MS = 340;
+ public static final Interpolator INTERPOLATOR = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
+ private static final int DIRECTION_NONE = 0;
+ private static final int DIRECTION_SHOW = 1;
+ private static final int DIRECTION_HIDE = 2;
+ private static final int FLOATING_IME_BOTTOM_INSET = -80;
+
+ protected final IWindowManager mWmService;
+ protected final Handler mHandler;
+ private final TransactionPool mTransactionPool;
+ private final DisplayController mDisplayController;
+ private final SparseArray<PerDisplay> mImePerDisplay = new SparseArray<>();
+ private final ArrayList<ImePositionProcessor> mPositionProcessors = new ArrayList<>();
+
+ protected DisplayImeController(IWindowManager wmService, DisplayController displayController,
+ Handler mainHandler, TransactionPool transactionPool) {
+ mHandler = mainHandler;
+ mWmService = wmService;
+ mTransactionPool = transactionPool;
+ mDisplayController = displayController;
+ }
+
+ protected void startMonitorDisplays() {
+ mDisplayController.addDisplayWindowListener(this);
+ }
+
+ @Override
+ public void onDisplayAdded(int displayId) {
+ // Add's a system-ui window-manager specifically for ime. This type is special because
+ // WM will defer IME inset handling to it in multi-window scenarious.
+ PerDisplay pd = new PerDisplay(displayId,
+ mDisplayController.getDisplayLayout(displayId).rotation());
+ try {
+ mWmService.setDisplayWindowInsetsController(displayId, pd);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Unable to set insets controller on display " + displayId);
+ }
+ mImePerDisplay.put(displayId, pd);
+ }
+
+ @Override
+ public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
+ PerDisplay pd = mImePerDisplay.get(displayId);
+ if (pd == null) {
+ return;
+ }
+ if (mDisplayController.getDisplayLayout(displayId).rotation()
+ != pd.mRotation && isImeShowing(displayId)) {
+ pd.startAnimation(true, false /* forceRestart */);
+ }
+ }
+
+ @Override
+ public void onDisplayRemoved(int displayId) {
+ try {
+ mWmService.setDisplayWindowInsetsController(displayId, null);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Unable to remove insets controller on display " + displayId);
+ }
+ mImePerDisplay.remove(displayId);
+ }
+
+ private boolean isImeShowing(int displayId) {
+ PerDisplay pd = mImePerDisplay.get(displayId);
+ if (pd == null) {
+ return false;
+ }
+ final InsetsSource imeSource = pd.mInsetsState.getSource(InsetsState.ITYPE_IME);
+ return imeSource != null && pd.mImeSourceControl != null && imeSource.isVisible();
+ }
+
+ private void dispatchPositionChanged(int displayId, int imeTop,
+ SurfaceControl.Transaction t) {
+ synchronized (mPositionProcessors) {
+ for (ImePositionProcessor pp : mPositionProcessors) {
+ pp.onImePositionChanged(displayId, imeTop, t);
+ }
+ }
+ }
+
+ @ImePositionProcessor.ImeAnimationFlags
+ private int dispatchStartPositioning(int displayId, int hiddenTop, int shownTop,
+ boolean show, boolean isFloating, SurfaceControl.Transaction t) {
+ synchronized (mPositionProcessors) {
+ int flags = 0;
+ for (ImePositionProcessor pp : mPositionProcessors) {
+ flags |= pp.onImeStartPositioning(
+ displayId, hiddenTop, shownTop, show, isFloating, t);
+ }
+ return flags;
+ }
+ }
+
+ private void dispatchEndPositioning(int displayId, boolean cancel,
+ SurfaceControl.Transaction t) {
+ synchronized (mPositionProcessors) {
+ for (ImePositionProcessor pp : mPositionProcessors) {
+ pp.onImeEndPositioning(displayId, cancel, t);
+ }
+ }
+ }
+
+ /**
+ * Adds an {@link ImePositionProcessor} to be called during ime position updates.
+ */
+ public void addPositionProcessor(ImePositionProcessor processor) {
+ synchronized (mPositionProcessors) {
+ if (mPositionProcessors.contains(processor)) {
+ return;
+ }
+ mPositionProcessors.add(processor);
+ }
+ }
+
+ /**
+ * Removes an {@link ImePositionProcessor} to be called during ime position updates.
+ */
+ public void removePositionProcessor(ImePositionProcessor processor) {
+ synchronized (mPositionProcessors) {
+ mPositionProcessors.remove(processor);
+ }
+ }
+
+ class PerDisplay extends IDisplayWindowInsetsController.Stub {
+ final int mDisplayId;
+ final InsetsState mInsetsState = new InsetsState();
+ InsetsSourceControl mImeSourceControl = null;
+ int mAnimationDirection = DIRECTION_NONE;
+ ValueAnimator mAnimation = null;
+ int mRotation = Surface.ROTATION_0;
+ boolean mImeShowing = false;
+ final Rect mImeFrame = new Rect();
+ boolean mAnimateAlpha = true;
+
+ PerDisplay(int displayId, int initialRotation) {
+ mDisplayId = displayId;
+ mRotation = initialRotation;
+ }
+
+ @Override
+ public void insetsChanged(InsetsState insetsState) {
+ mHandler.post(() -> {
+ if (mInsetsState.equals(insetsState)) {
+ return;
+ }
+
+ final InsetsSource newSource = insetsState.getSource(InsetsState.ITYPE_IME);
+ final Rect newFrame = newSource.getFrame();
+ final Rect oldFrame = mInsetsState.getSource(InsetsState.ITYPE_IME).getFrame();
+
+ mInsetsState.set(insetsState, true /* copySources */);
+ if (mImeShowing && !newFrame.equals(oldFrame) && newSource.isVisible()) {
+ if (DEBUG) Slog.d(TAG, "insetsChanged when IME showing, restart animation");
+ startAnimation(mImeShowing, true /* forceRestart */);
+ }
+ });
+ }
+
+ @Override
+ public void insetsControlChanged(InsetsState insetsState,
+ InsetsSourceControl[] activeControls) {
+ insetsChanged(insetsState);
+ if (activeControls != null) {
+ for (InsetsSourceControl activeControl : activeControls) {
+ if (activeControl == null) {
+ continue;
+ }
+ if (activeControl.getType() == InsetsState.ITYPE_IME) {
+ mHandler.post(() -> {
+ final Point lastSurfacePosition = mImeSourceControl != null
+ ? mImeSourceControl.getSurfacePosition() : null;
+ mImeSourceControl = activeControl;
+ if (!activeControl.getSurfacePosition().equals(lastSurfacePosition)
+ && mAnimation != null) {
+ startAnimation(mImeShowing, true /* forceRestart */);
+ } else if (!mImeShowing) {
+ removeImeSurface();
+ }
+ });
+ }
+ }
+ }
+ }
+
+ @Override
+ public void showInsets(int types, boolean fromIme) {
+ if ((types & WindowInsets.Type.ime()) == 0) {
+ return;
+ }
+ if (DEBUG) Slog.d(TAG, "Got showInsets for ime");
+ mHandler.post(() -> startAnimation(true /* show */, false /* forceRestart */));
+ }
+
+ @Override
+ public void hideInsets(int types, boolean fromIme) {
+ if ((types & WindowInsets.Type.ime()) == 0) {
+ return;
+ }
+ if (DEBUG) Slog.d(TAG, "Got hideInsets for ime");
+ mHandler.post(() -> startAnimation(false /* show */, false /* forceRestart */));
+ }
+
+ @Override
+ public void topFocusedWindowChanged(String packageName) {
+ // no-op
+ }
+
+ /**
+ * Sends the local visibility state back to window manager. Needed for legacy adjustForIme.
+ */
+ private void setVisibleDirectly(boolean visible) {
+ mInsetsState.getSource(InsetsState.ITYPE_IME).setVisible(visible);
+ try {
+ mWmService.modifyDisplayWindowInsets(mDisplayId, mInsetsState);
+ } catch (RemoteException e) {
+ }
+ }
+
+ private int imeTop(float surfaceOffset) {
+ return mImeFrame.top + (int) surfaceOffset;
+ }
+
+ private boolean calcIsFloating(InsetsSource imeSource) {
+ final Rect frame = imeSource.getFrame();
+ if (frame.height() == 0) {
+ return true;
+ }
+ // Some Floating Input Methods will still report a frame, but the frame is actually
+ // a nav-bar inset created by WM and not part of the IME (despite being reported as
+ // an IME inset). For now, we assume that no non-floating IME will be <= this nav bar
+ // frame height so any reported frame that is <= nav-bar frame height is assumed to
+ // be floating.
+ return frame.height() <= mDisplayController.getDisplayLayout(mDisplayId)
+ .navBarFrameHeight();
+ }
+
+ private void startAnimation(final boolean show, final boolean forceRestart) {
+ final InsetsSource imeSource = mInsetsState.getSource(InsetsState.ITYPE_IME);
+ if (imeSource == null || mImeSourceControl == null) {
+ return;
+ }
+ final Rect newFrame = imeSource.getFrame();
+ final boolean isFloating = calcIsFloating(imeSource) && show;
+ if (isFloating) {
+ // This is a "floating" or "expanded" IME, so to get animations, just
+ // pretend the ime has some size just below the screen.
+ mImeFrame.set(newFrame);
+ final int floatingInset = (int) (mDisplayController.getDisplayLayout(mDisplayId)
+ .density() * FLOATING_IME_BOTTOM_INSET);
+ mImeFrame.bottom -= floatingInset;
+ } else if (newFrame.height() != 0) {
+ // Don't set a new frame if it's empty and hiding -- this maintains continuity
+ mImeFrame.set(newFrame);
+ }
+ if (DEBUG) {
+ Slog.d(TAG, "Run startAnim show:" + show + " was:"
+ + (mAnimationDirection == DIRECTION_SHOW ? "SHOW"
+ : (mAnimationDirection == DIRECTION_HIDE ? "HIDE" : "NONE")));
+ }
+ if (!forceRestart && (mAnimationDirection == DIRECTION_SHOW && show)
+ || (mAnimationDirection == DIRECTION_HIDE && !show)) {
+ return;
+ }
+ boolean seek = false;
+ float seekValue = 0;
+ if (mAnimation != null) {
+ if (mAnimation.isRunning()) {
+ seekValue = (float) mAnimation.getAnimatedValue();
+ seek = true;
+ }
+ mAnimation.cancel();
+ }
+ final float defaultY = mImeSourceControl.getSurfacePosition().y;
+ final float x = mImeSourceControl.getSurfacePosition().x;
+ final float hiddenY = defaultY + mImeFrame.height();
+ final float shownY = defaultY;
+ final float startY = show ? hiddenY : shownY;
+ final float endY = show ? shownY : hiddenY;
+ if (mAnimationDirection == DIRECTION_NONE && mImeShowing && show) {
+ // IME is already showing, so set seek to end
+ seekValue = shownY;
+ seek = true;
+ }
+ mAnimationDirection = show ? DIRECTION_SHOW : DIRECTION_HIDE;
+ mImeShowing = show;
+ mAnimation = ValueAnimator.ofFloat(startY, endY);
+ mAnimation.setDuration(
+ show ? ANIMATION_DURATION_SHOW_MS : ANIMATION_DURATION_HIDE_MS);
+ if (seek) {
+ mAnimation.setCurrentFraction((seekValue - startY) / (endY - startY));
+ }
+
+ mAnimation.addUpdateListener(animation -> {
+ SurfaceControl.Transaction t = mTransactionPool.acquire();
+ float value = (float) animation.getAnimatedValue();
+ t.setPosition(mImeSourceControl.getLeash(), x, value);
+ final float alpha = (mAnimateAlpha || isFloating)
+ ? (value - hiddenY) / (shownY - hiddenY) : 1.f;
+ t.setAlpha(mImeSourceControl.getLeash(), alpha);
+ dispatchPositionChanged(mDisplayId, imeTop(value), t);
+ t.apply();
+ mTransactionPool.release(t);
+ });
+ mAnimation.setInterpolator(INTERPOLATOR);
+ mAnimation.addListener(new AnimatorListenerAdapter() {
+ private boolean mCancelled = false;
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ SurfaceControl.Transaction t = mTransactionPool.acquire();
+ t.setPosition(mImeSourceControl.getLeash(), x, startY);
+ if (DEBUG) {
+ Slog.d(TAG, "onAnimationStart d:" + mDisplayId + " top:"
+ + imeTop(hiddenY) + "->" + imeTop(shownY)
+ + " showing:" + (mAnimationDirection == DIRECTION_SHOW));
+ }
+ int flags = dispatchStartPositioning(mDisplayId, imeTop(hiddenY),
+ imeTop(shownY), mAnimationDirection == DIRECTION_SHOW, isFloating, t);
+ mAnimateAlpha = (flags & ImePositionProcessor.IME_ANIMATION_NO_ALPHA) == 0;
+ final float alpha = (mAnimateAlpha || isFloating)
+ ? (startY - hiddenY) / (shownY - hiddenY)
+ : 1.f;
+ t.setAlpha(mImeSourceControl.getLeash(), alpha);
+ if (mAnimationDirection == DIRECTION_SHOW) {
+ t.show(mImeSourceControl.getLeash());
+ }
+ t.apply();
+ mTransactionPool.release(t);
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mCancelled = true;
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (DEBUG) Slog.d(TAG, "onAnimationEnd " + mCancelled);
+ SurfaceControl.Transaction t = mTransactionPool.acquire();
+ if (!mCancelled) {
+ t.setPosition(mImeSourceControl.getLeash(), x, endY);
+ t.setAlpha(mImeSourceControl.getLeash(), 1.f);
+ }
+ dispatchEndPositioning(mDisplayId, mCancelled, t);
+ if (mAnimationDirection == DIRECTION_HIDE && !mCancelled) {
+ t.hide(mImeSourceControl.getLeash());
+ removeImeSurface();
+ }
+ t.apply();
+ mTransactionPool.release(t);
+
+ mAnimationDirection = DIRECTION_NONE;
+ mAnimation = null;
+ }
+ });
+ if (!show) {
+ // When going away, queue up insets change first, otherwise any bounds changes
+ // can have a "flicker" of ime-provided insets.
+ setVisibleDirectly(false /* visible */);
+ }
+ mAnimation.start();
+ if (show) {
+ // When showing away, queue up insets change last, otherwise any bounds changes
+ // can have a "flicker" of ime-provided insets.
+ setVisibleDirectly(true /* visible */);
+ }
+ }
+ }
+
+ void removeImeSurface() {
+ final IInputMethodManager imms = getImms();
+ if (imms != null) {
+ try {
+ // Remove the IME surface to make the insets invisible for
+ // non-client controlled insets.
+ imms.removeImeSurface();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to remove IME surface.", e);
+ }
+ }
+ }
+
+ /**
+ * Allows other things to synchronize with the ime position
+ */
+ public interface ImePositionProcessor {
+ /**
+ * Indicates that ime shouldn't animate alpha. It will always be opaque. Used when stuff
+ * behind the IME shouldn't be visible (for example during split-screen adjustment where
+ * there is nothing behind the ime).
+ */
+ int IME_ANIMATION_NO_ALPHA = 1;
+
+ /** @hide */
+ @IntDef(prefix = {"IME_ANIMATION_"}, value = {
+ IME_ANIMATION_NO_ALPHA,
+ })
+ @interface ImeAnimationFlags {
+ }
+
+ /**
+ * Called when the IME position is starting to animate.
+ *
+ * @param hiddenTop The y position of the top of the IME surface when it is hidden.
+ * @param shownTop The y position of the top of the IME surface when it is shown.
+ * @param showing {@code true} when we are animating from hidden to shown, {@code false}
+ * when animating from shown to hidden.
+ * @param isFloating {@code true} when the ime is a floating ime (doesn't inset).
+ * @return flags that may alter how ime itself is animated (eg. no-alpha).
+ */
+ @ImeAnimationFlags
+ default int onImeStartPositioning(int displayId, int hiddenTop, int shownTop,
+ boolean showing, boolean isFloating, SurfaceControl.Transaction t) {
+ return 0;
+ }
+
+ /**
+ * Called when the ime position changed. This is expected to be a synchronous call on the
+ * animation thread. Operations can be added to the transaction to be applied in sync.
+ *
+ * @param imeTop The current y position of the top of the IME surface.
+ */
+ default void onImePositionChanged(int displayId, int imeTop, SurfaceControl.Transaction t) {
+ }
+
+ /**
+ * Called when the IME position is done animating.
+ *
+ * @param cancel {@code true} if this was cancelled. This implies another start is coming.
+ */
+ default void onImeEndPositioning(int displayId, boolean cancel,
+ SurfaceControl.Transaction t) {
+ }
+ }
+
+ public IInputMethodManager getImms() {
+ return IInputMethodManager.Stub.asInterface(
+ ServiceManager.getService(Context.INPUT_METHOD_SERVICE));
+ }
+
+ /** Builds {@link DisplayImeController} instance. */
+ public static class Builder {
+ private IWindowManager mWmService;
+ private DisplayController mDisplayController;
+ private Handler mHandler;
+ private TransactionPool mTransactionPool;
+
+ public Builder(IWindowManager wmService, DisplayController displayController,
+ Handler handler, TransactionPool transactionPool) {
+ mWmService = wmService;
+ mDisplayController = displayController;
+ mHandler = handler;
+ mTransactionPool = transactionPool;
+ }
+
+ /** Builds and initializes {@link DisplayImeController} instance. */
+ public DisplayImeController build() {
+ DisplayImeController displayImeController = new DisplayImeController(mWmService,
+ mDisplayController, mHandler, mTransactionPool);
+ // Separates startMonitorDisplays from constructor to prevent circular init issue.
+ displayImeController.startMonitorDisplays();
+ return displayImeController;
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
new file mode 100644
index 000000000000..3181dbf74ace
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
@@ -0,0 +1,511 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.common;
+
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static android.content.res.Configuration.UI_MODE_TYPE_CAR;
+import static android.content.res.Configuration.UI_MODE_TYPE_MASK;
+import static android.os.Process.SYSTEM_UID;
+import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS;
+import static android.view.Display.FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS;
+import static android.view.Surface.ROTATION_0;
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Insets;
+import android.graphics.Rect;
+import android.os.SystemProperties;
+import android.provider.Settings;
+import android.util.DisplayMetrics;
+import android.util.RotationUtils;
+import android.util.Size;
+import android.view.Display;
+import android.view.DisplayCutout;
+import android.view.DisplayInfo;
+import android.view.Gravity;
+import android.view.Surface;
+
+import com.android.internal.R;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Contains information about the layout-properties of a display. This refers to internal layout
+ * like insets/cutout/rotation. In general, this can be thought of as the shell analog to
+ * DisplayPolicy.
+ */
+public class DisplayLayout {
+ @IntDef(prefix = { "NAV_BAR_" }, value = {
+ NAV_BAR_LEFT,
+ NAV_BAR_RIGHT,
+ NAV_BAR_BOTTOM,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface NavBarPosition {}
+
+ // Navigation bar position values
+ public static final int NAV_BAR_LEFT = 1 << 0;
+ public static final int NAV_BAR_RIGHT = 1 << 1;
+ public static final int NAV_BAR_BOTTOM = 1 << 2;
+
+ private int mUiMode;
+ private int mWidth;
+ private int mHeight;
+ private DisplayCutout mCutout;
+ private int mRotation;
+ private int mDensityDpi;
+ private final Rect mNonDecorInsets = new Rect();
+ private final Rect mStableInsets = new Rect();
+ private boolean mHasNavigationBar = false;
+ private boolean mHasStatusBar = false;
+ private int mNavBarFrameHeight = 0;
+
+ /**
+ * Create empty layout.
+ */
+ public DisplayLayout() {
+ }
+
+ /**
+ * Construct a custom display layout using a DisplayInfo.
+ * @param info
+ * @param res
+ */
+ public DisplayLayout(DisplayInfo info, Resources res, boolean hasNavigationBar,
+ boolean hasStatusBar) {
+ init(info, res, hasNavigationBar, hasStatusBar);
+ }
+
+ /**
+ * Construct a display layout based on a live display.
+ * @param context Used for resources.
+ */
+ public DisplayLayout(@NonNull Context context, @NonNull Display rawDisplay) {
+ final int displayId = rawDisplay.getDisplayId();
+ DisplayInfo info = new DisplayInfo();
+ rawDisplay.getDisplayInfo(info);
+ init(info, context.getResources(), hasNavigationBar(info, context, displayId),
+ hasStatusBar(displayId));
+ }
+
+ public DisplayLayout(DisplayLayout dl) {
+ set(dl);
+ }
+
+ /** sets this DisplayLayout to a copy of another on. */
+ public void set(DisplayLayout dl) {
+ mUiMode = dl.mUiMode;
+ mWidth = dl.mWidth;
+ mHeight = dl.mHeight;
+ mCutout = dl.mCutout;
+ mRotation = dl.mRotation;
+ mDensityDpi = dl.mDensityDpi;
+ mHasNavigationBar = dl.mHasNavigationBar;
+ mHasStatusBar = dl.mHasStatusBar;
+ mNonDecorInsets.set(dl.mNonDecorInsets);
+ mStableInsets.set(dl.mStableInsets);
+ }
+
+ private void init(DisplayInfo info, Resources res, boolean hasNavigationBar,
+ boolean hasStatusBar) {
+ mUiMode = res.getConfiguration().uiMode;
+ mWidth = info.logicalWidth;
+ mHeight = info.logicalHeight;
+ mRotation = info.rotation;
+ mCutout = info.displayCutout;
+ mDensityDpi = info.logicalDensityDpi;
+ mHasNavigationBar = hasNavigationBar;
+ mHasStatusBar = hasStatusBar;
+ recalcInsets(res);
+ }
+
+ private void recalcInsets(Resources res) {
+ computeNonDecorInsets(res, mRotation, mWidth, mHeight, mCutout, mUiMode, mNonDecorInsets,
+ mHasNavigationBar);
+ mStableInsets.set(mNonDecorInsets);
+ if (mHasStatusBar) {
+ convertNonDecorInsetsToStableInsets(res, mStableInsets, mWidth, mHeight, mHasStatusBar);
+ }
+ mNavBarFrameHeight = getNavigationBarFrameHeight(res, mWidth > mHeight);
+ }
+
+ /**
+ * Apply a rotation to this layout and its parameters.
+ * @param res
+ * @param targetRotation
+ */
+ public void rotateTo(Resources res, @Surface.Rotation int targetRotation) {
+ final int rotationDelta = (targetRotation - mRotation + 4) % 4;
+ final boolean changeOrient = (rotationDelta % 2) != 0;
+
+ final int origWidth = mWidth;
+ final int origHeight = mHeight;
+
+ mRotation = targetRotation;
+ if (changeOrient) {
+ mWidth = origHeight;
+ mHeight = origWidth;
+ }
+
+ if (mCutout != null && !mCutout.isEmpty()) {
+ mCutout = calculateDisplayCutoutForRotation(mCutout, rotationDelta, origWidth,
+ origHeight);
+ }
+
+ recalcInsets(res);
+ }
+
+ /** Get this layout's non-decor insets. */
+ public Rect nonDecorInsets() {
+ return mNonDecorInsets;
+ }
+
+ /** Get this layout's stable insets. */
+ public Rect stableInsets() {
+ return mStableInsets;
+ }
+
+ /** Get this layout's width. */
+ public int width() {
+ return mWidth;
+ }
+
+ /** Get this layout's height. */
+ public int height() {
+ return mHeight;
+ }
+
+ /** Get this layout's display rotation. */
+ public int rotation() {
+ return mRotation;
+ }
+
+ /** Get this layout's display density. */
+ public int densityDpi() {
+ return mDensityDpi;
+ }
+
+ /** Get the density scale for the display. */
+ public float density() {
+ return mDensityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
+ }
+
+ /** Get whether this layout is landscape. */
+ public boolean isLandscape() {
+ return mWidth > mHeight;
+ }
+
+ /** Get the navbar frame height (used by ime). */
+ public int navBarFrameHeight() {
+ return mNavBarFrameHeight;
+ }
+
+ /** Gets the orientation of this layout */
+ public int getOrientation() {
+ return (mWidth > mHeight) ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT;
+ }
+
+ /** Gets the calculated stable-bounds for this layout */
+ public void getStableBounds(Rect outBounds) {
+ outBounds.set(0, 0, mWidth, mHeight);
+ outBounds.inset(mStableInsets);
+ }
+
+ /**
+ * Gets navigation bar position for this layout
+ * @return Navigation bar position for this layout.
+ */
+ public @NavBarPosition int getNavigationBarPosition(Resources res) {
+ return navigationBarPosition(res, mWidth, mHeight, mRotation);
+ }
+
+ /**
+ * Rotates bounds as if parentBounds and bounds are a group. The group is rotated by `delta`
+ * 90-degree counter-clockwise increments. This assumes that parentBounds is at 0,0 and
+ * remains at 0,0 after rotation.
+ *
+ * Only 'bounds' is mutated.
+ */
+ public static void rotateBounds(Rect inOutBounds, Rect parentBounds, int delta) {
+ int rdelta = ((delta % 4) + 4) % 4;
+ int origLeft = inOutBounds.left;
+ switch (rdelta) {
+ case 0:
+ return;
+ case 1:
+ inOutBounds.left = inOutBounds.top;
+ inOutBounds.top = parentBounds.right - inOutBounds.right;
+ inOutBounds.right = inOutBounds.bottom;
+ inOutBounds.bottom = parentBounds.right - origLeft;
+ return;
+ case 2:
+ inOutBounds.left = parentBounds.right - inOutBounds.right;
+ inOutBounds.right = parentBounds.right - origLeft;
+ return;
+ case 3:
+ inOutBounds.left = parentBounds.bottom - inOutBounds.bottom;
+ inOutBounds.bottom = inOutBounds.right;
+ inOutBounds.right = parentBounds.bottom - inOutBounds.top;
+ inOutBounds.top = origLeft;
+ return;
+ }
+ }
+
+ /**
+ * Calculates the stable insets if we already have the non-decor insets.
+ */
+ private static void convertNonDecorInsetsToStableInsets(Resources res, Rect inOutInsets,
+ int displayWidth, int displayHeight, boolean hasStatusBar) {
+ if (!hasStatusBar) {
+ return;
+ }
+ int statusBarHeight = getStatusBarHeight(displayWidth > displayHeight, res);
+ inOutInsets.top = Math.max(inOutInsets.top, statusBarHeight);
+ }
+
+ /**
+ * Calculates the insets for the areas that could never be removed in Honeycomb, i.e. system
+ * bar or button bar.
+ *
+ * @param displayRotation the current display rotation
+ * @param displayWidth the current display width
+ * @param displayHeight the current display height
+ * @param displayCutout the current display cutout
+ * @param outInsets the insets to return
+ */
+ static void computeNonDecorInsets(Resources res, int displayRotation, int displayWidth,
+ int displayHeight, DisplayCutout displayCutout, int uiMode, Rect outInsets,
+ boolean hasNavigationBar) {
+ outInsets.setEmpty();
+
+ // Only navigation bar
+ if (hasNavigationBar) {
+ int position = navigationBarPosition(res, displayWidth, displayHeight, displayRotation);
+ int navBarSize =
+ getNavigationBarSize(res, position, displayWidth > displayHeight, uiMode);
+ if (position == NAV_BAR_BOTTOM) {
+ outInsets.bottom = navBarSize;
+ } else if (position == NAV_BAR_RIGHT) {
+ outInsets.right = navBarSize;
+ } else if (position == NAV_BAR_LEFT) {
+ outInsets.left = navBarSize;
+ }
+ }
+
+ if (displayCutout != null) {
+ outInsets.left += displayCutout.getSafeInsetLeft();
+ outInsets.top += displayCutout.getSafeInsetTop();
+ outInsets.right += displayCutout.getSafeInsetRight();
+ outInsets.bottom += displayCutout.getSafeInsetBottom();
+ }
+ }
+
+ /**
+ * Calculates the stable insets without running a layout.
+ *
+ * @param displayRotation the current display rotation
+ * @param displayWidth the current display width
+ * @param displayHeight the current display height
+ * @param displayCutout the current display cutout
+ * @param outInsets the insets to return
+ */
+ static void computeStableInsets(Resources res, int displayRotation, int displayWidth,
+ int displayHeight, DisplayCutout displayCutout, int uiMode, Rect outInsets,
+ boolean hasNavigationBar, boolean hasStatusBar) {
+ outInsets.setEmpty();
+
+ // Navigation bar and status bar.
+ computeNonDecorInsets(res, displayRotation, displayWidth, displayHeight, displayCutout,
+ uiMode, outInsets, hasNavigationBar);
+ convertNonDecorInsetsToStableInsets(res, outInsets, displayWidth, displayHeight,
+ hasStatusBar);
+ }
+
+ /** Retrieve the statusbar height from resources. */
+ static int getStatusBarHeight(boolean landscape, Resources res) {
+ return landscape ? res.getDimensionPixelSize(
+ com.android.internal.R.dimen.status_bar_height_landscape)
+ : res.getDimensionPixelSize(
+ com.android.internal.R.dimen.status_bar_height_portrait);
+ }
+
+ /** Calculate the DisplayCutout for a particular display size/rotation. */
+ public static DisplayCutout calculateDisplayCutoutForRotation(
+ DisplayCutout cutout, int rotation, int displayWidth, int displayHeight) {
+ if (cutout == null || cutout == DisplayCutout.NO_CUTOUT) {
+ return null;
+ }
+ final Insets waterfallInsets =
+ RotationUtils.rotateInsets(cutout.getWaterfallInsets(), rotation);
+ if (rotation == ROTATION_0) {
+ return computeSafeInsets(cutout, displayWidth, displayHeight);
+ }
+ final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
+ Rect[] cutoutRects = cutout.getBoundingRectsAll();
+ final Rect[] newBounds = new Rect[cutoutRects.length];
+ final Rect displayBounds = new Rect(0, 0, displayWidth, displayHeight);
+ for (int i = 0; i < cutoutRects.length; ++i) {
+ final Rect rect = new Rect(cutoutRects[i]);
+ if (!rect.isEmpty()) {
+ rotateBounds(rect, displayBounds, rotation);
+ }
+ newBounds[getBoundIndexFromRotation(i, rotation)] = rect;
+ }
+ return computeSafeInsets(
+ DisplayCutout.fromBoundsAndWaterfall(newBounds, waterfallInsets),
+ rotated ? displayHeight : displayWidth,
+ rotated ? displayWidth : displayHeight);
+ }
+
+ private static int getBoundIndexFromRotation(int index, int rotation) {
+ return (index - rotation) < 0
+ ? index - rotation + DisplayCutout.BOUNDS_POSITION_LENGTH
+ : index - rotation;
+ }
+
+ /** Calculate safe insets. */
+ public static DisplayCutout computeSafeInsets(DisplayCutout inner,
+ int displayWidth, int displayHeight) {
+ if (inner == DisplayCutout.NO_CUTOUT) {
+ return null;
+ }
+
+ final Size displaySize = new Size(displayWidth, displayHeight);
+ final Rect safeInsets = computeSafeInsets(displaySize, inner);
+ return inner.replaceSafeInsets(safeInsets);
+ }
+
+ private static Rect computeSafeInsets(
+ Size displaySize, DisplayCutout cutout) {
+ if (displaySize.getWidth() == displaySize.getHeight()) {
+ throw new UnsupportedOperationException("not implemented: display=" + displaySize
+ + " cutout=" + cutout);
+ }
+
+ int leftInset = Math.max(cutout.getWaterfallInsets().left,
+ findCutoutInsetForSide(displaySize, cutout.getBoundingRectLeft(), Gravity.LEFT));
+ int topInset = Math.max(cutout.getWaterfallInsets().top,
+ findCutoutInsetForSide(displaySize, cutout.getBoundingRectTop(), Gravity.TOP));
+ int rightInset = Math.max(cutout.getWaterfallInsets().right,
+ findCutoutInsetForSide(displaySize, cutout.getBoundingRectRight(), Gravity.RIGHT));
+ int bottomInset = Math.max(cutout.getWaterfallInsets().bottom,
+ findCutoutInsetForSide(displaySize, cutout.getBoundingRectBottom(),
+ Gravity.BOTTOM));
+
+ return new Rect(leftInset, topInset, rightInset, bottomInset);
+ }
+
+ private static int findCutoutInsetForSide(Size display, Rect boundingRect, int gravity) {
+ if (boundingRect.isEmpty()) {
+ return 0;
+ }
+
+ int inset = 0;
+ switch (gravity) {
+ case Gravity.TOP:
+ return Math.max(inset, boundingRect.bottom);
+ case Gravity.BOTTOM:
+ return Math.max(inset, display.getHeight() - boundingRect.top);
+ case Gravity.LEFT:
+ return Math.max(inset, boundingRect.right);
+ case Gravity.RIGHT:
+ return Math.max(inset, display.getWidth() - boundingRect.left);
+ default:
+ throw new IllegalArgumentException("unknown gravity: " + gravity);
+ }
+ }
+
+ static boolean hasNavigationBar(DisplayInfo info, Context context, int displayId) {
+ if (displayId == Display.DEFAULT_DISPLAY) {
+ // Allow a system property to override this. Used by the emulator.
+ final String navBarOverride = SystemProperties.get("qemu.hw.mainkeys");
+ if ("1".equals(navBarOverride)) {
+ return false;
+ } else if ("0".equals(navBarOverride)) {
+ return true;
+ }
+ return context.getResources().getBoolean(R.bool.config_showNavigationBar);
+ } else {
+ boolean isUntrustedVirtualDisplay = info.type == Display.TYPE_VIRTUAL
+ && info.ownerUid != SYSTEM_UID;
+ final ContentResolver resolver = context.getContentResolver();
+ boolean forceDesktopOnExternal = Settings.Global.getInt(resolver,
+ DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS, 0) != 0;
+
+ return ((info.flags & FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS) != 0
+ || (forceDesktopOnExternal && !isUntrustedVirtualDisplay));
+ // TODO(b/142569966): make sure VR2D and DisplayWindowSettings are moved here somehow.
+ }
+ }
+
+ static boolean hasStatusBar(int displayId) {
+ return displayId == Display.DEFAULT_DISPLAY;
+ }
+
+ /** Retrieve navigation bar position from resources based on rotation and size. */
+ public static @NavBarPosition int navigationBarPosition(Resources res, int displayWidth,
+ int displayHeight, int rotation) {
+ boolean navBarCanMove = displayWidth != displayHeight && res.getBoolean(
+ com.android.internal.R.bool.config_navBarCanMove);
+ if (navBarCanMove && displayWidth > displayHeight) {
+ if (rotation == Surface.ROTATION_90) {
+ return NAV_BAR_RIGHT;
+ } else {
+ return NAV_BAR_LEFT;
+ }
+ }
+ return NAV_BAR_BOTTOM;
+ }
+
+ /** Retrieve navigation bar size from resources based on side/orientation/ui-mode */
+ public static int getNavigationBarSize(Resources res, int navBarSide, boolean landscape,
+ int uiMode) {
+ final boolean carMode = (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR;
+ if (carMode) {
+ if (navBarSide == NAV_BAR_BOTTOM) {
+ return res.getDimensionPixelSize(landscape
+ ? R.dimen.navigation_bar_height_landscape_car_mode
+ : R.dimen.navigation_bar_height_car_mode);
+ } else {
+ return res.getDimensionPixelSize(R.dimen.navigation_bar_width_car_mode);
+ }
+
+ } else {
+ if (navBarSide == NAV_BAR_BOTTOM) {
+ return res.getDimensionPixelSize(landscape
+ ? R.dimen.navigation_bar_height_landscape
+ : R.dimen.navigation_bar_height);
+ } else {
+ return res.getDimensionPixelSize(R.dimen.navigation_bar_width);
+ }
+ }
+ }
+
+ /** @see com.android.server.wm.DisplayPolicy#getNavigationBarFrameHeight */
+ public static int getNavigationBarFrameHeight(Resources res, boolean landscape) {
+ return res.getDimensionPixelSize(landscape
+ ? R.dimen.navigation_bar_frame_height_landscape
+ : R.dimen.navigation_bar_frame_height);
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
new file mode 100644
index 000000000000..8abe9eeb6a9a
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
@@ -0,0 +1,393 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.common;
+
+import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.graphics.Region;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.util.MergedConfiguration;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.view.Display;
+import android.view.DisplayCutout;
+import android.view.DragEvent;
+import android.view.IScrollCaptureController;
+import android.view.IWindow;
+import android.view.IWindowManager;
+import android.view.IWindowSession;
+import android.view.IWindowSessionCallback;
+import android.view.InsetsSourceControl;
+import android.view.InsetsState;
+import android.view.SurfaceControl;
+import android.view.SurfaceControlViewHost;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.view.WindowlessWindowManager;
+
+import com.android.internal.os.IResultReceiver;
+
+import java.util.HashMap;
+
+/**
+ * Represents the "windowing" layer of the WM Shell. This layer allows shell components to place and
+ * manipulate windows without talking to WindowManager.
+ */
+public class SystemWindows {
+ private static final String TAG = "SystemWindows";
+
+ private final SparseArray<PerDisplay> mPerDisplay = new SparseArray<>();
+ private final HashMap<View, SurfaceControlViewHost> mViewRoots = new HashMap<>();
+ private final DisplayController mDisplayController;
+ private final IWindowManager mWmService;
+ private IWindowSession mSession;
+
+ private final DisplayController.OnDisplaysChangedListener mDisplayListener =
+ new DisplayController.OnDisplaysChangedListener() {
+ @Override
+ public void onDisplayAdded(int displayId) { }
+
+ @Override
+ public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
+ PerDisplay pd = mPerDisplay.get(displayId);
+ if (pd == null) {
+ return;
+ }
+ pd.updateConfiguration(newConfig);
+ }
+
+ @Override
+ public void onDisplayRemoved(int displayId) { }
+ };
+
+ public SystemWindows(DisplayController displayController, IWindowManager wmService) {
+ mWmService = wmService;
+ mDisplayController = displayController;
+ mDisplayController.addDisplayWindowListener(mDisplayListener);
+ try {
+ mSession = wmService.openSession(
+ new IWindowSessionCallback.Stub() {
+ @Override
+ public void onAnimatorScaleChanged(float scale) {}
+ });
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to create layer", e);
+ }
+ }
+
+ /**
+ * Adds a view to system-ui window management.
+ */
+ public void addView(View view, WindowManager.LayoutParams attrs, int displayId,
+ int windowType) {
+ PerDisplay pd = mPerDisplay.get(displayId);
+ if (pd == null) {
+ pd = new PerDisplay(displayId);
+ mPerDisplay.put(displayId, pd);
+ }
+ pd.addView(view, attrs, windowType);
+ }
+
+ /**
+ * Removes a view from system-ui window management.
+ * @param view
+ */
+ public void removeView(View view) {
+ SurfaceControlViewHost root = mViewRoots.remove(view);
+ root.release();
+ }
+
+ /**
+ * Updates the layout params of a view.
+ */
+ public void updateViewLayout(@NonNull View view, ViewGroup.LayoutParams params) {
+ SurfaceControlViewHost root = mViewRoots.get(view);
+ if (root == null || !(params instanceof WindowManager.LayoutParams)) {
+ return;
+ }
+ view.setLayoutParams(params);
+ root.relayout((WindowManager.LayoutParams) params);
+ }
+
+ /**
+ * Sets the touchable region of a view's window. This will be cropped to the window size.
+ * @param view
+ * @param region
+ */
+ public void setTouchableRegion(@NonNull View view, Region region) {
+ SurfaceControlViewHost root = mViewRoots.get(view);
+ if (root == null) {
+ return;
+ }
+ WindowlessWindowManager wwm = root.getWindowlessWM();
+ if (!(wwm instanceof SysUiWindowManager)) {
+ return;
+ }
+ ((SysUiWindowManager) wwm).setTouchableRegionForWindow(view, region);
+ }
+
+ /**
+ * Adds a root for system-ui window management with no views. Only useful for IME.
+ */
+ public void addRoot(int displayId, int windowType) {
+ PerDisplay pd = mPerDisplay.get(displayId);
+ if (pd == null) {
+ pd = new PerDisplay(displayId);
+ mPerDisplay.put(displayId, pd);
+ }
+ pd.addRoot(windowType);
+ }
+
+ /**
+ * Get the IWindow token for a specific root.
+ *
+ * @param windowType A window type from {@link WindowManager}.
+ */
+ IWindow getWindow(int displayId, int windowType) {
+ PerDisplay pd = mPerDisplay.get(displayId);
+ if (pd == null) {
+ return null;
+ }
+ return pd.getWindow(windowType);
+ }
+
+ /**
+ * Gets the SurfaceControl associated with a root view. This is the same surface that backs the
+ * ViewRootImpl.
+ */
+ public SurfaceControl getViewSurface(View rootView) {
+ for (int i = 0; i < mPerDisplay.size(); ++i) {
+ for (int iWm = 0; iWm < mPerDisplay.valueAt(i).mWwms.size(); ++iWm) {
+ SurfaceControl out = mPerDisplay.valueAt(i).mWwms.valueAt(iWm)
+ .getSurfaceControlForWindow(rootView);
+ if (out != null) {
+ return out;
+ }
+ }
+ }
+ return null;
+ }
+
+ private class PerDisplay {
+ final int mDisplayId;
+ private final SparseArray<SysUiWindowManager> mWwms = new SparseArray<>();
+
+ PerDisplay(int displayId) {
+ mDisplayId = displayId;
+ }
+
+ public void addView(View view, WindowManager.LayoutParams attrs, int windowType) {
+ SysUiWindowManager wwm = addRoot(windowType);
+ if (wwm == null) {
+ Slog.e(TAG, "Unable to create systemui root");
+ return;
+ }
+ final Display display = mDisplayController.getDisplay(mDisplayId);
+ SurfaceControlViewHost viewRoot =
+ new SurfaceControlViewHost(
+ view.getContext(), display, wwm, true /* useSfChoreographer */);
+ attrs.flags |= FLAG_HARDWARE_ACCELERATED;
+ viewRoot.setView(view, attrs);
+ mViewRoots.put(view, viewRoot);
+
+ try {
+ mWmService.setShellRootAccessibilityWindow(mDisplayId, windowType,
+ viewRoot.getWindowToken());
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Error setting accessibility window for " + mDisplayId + ":"
+ + windowType, e);
+ }
+ }
+
+ SysUiWindowManager addRoot(int windowType) {
+ SysUiWindowManager wwm = mWwms.get(windowType);
+ if (wwm != null) {
+ return wwm;
+ }
+ SurfaceControl rootSurface = null;
+ ContainerWindow win = new ContainerWindow();
+ try {
+ rootSurface = mWmService.addShellRoot(mDisplayId, win, windowType);
+ } catch (RemoteException e) {
+ }
+ if (rootSurface == null) {
+ Slog.e(TAG, "Unable to get root surfacecontrol for systemui");
+ return null;
+ }
+ Context displayContext = mDisplayController.getDisplayContext(mDisplayId);
+ wwm = new SysUiWindowManager(mDisplayId, displayContext, rootSurface, win);
+ mWwms.put(windowType, wwm);
+ return wwm;
+ }
+
+ IWindow getWindow(int windowType) {
+ SysUiWindowManager wwm = mWwms.get(windowType);
+ if (wwm == null) {
+ return null;
+ }
+ return wwm.mContainerWindow;
+ }
+
+ void updateConfiguration(Configuration configuration) {
+ for (int i = 0; i < mWwms.size(); ++i) {
+ mWwms.valueAt(i).updateConfiguration(configuration);
+ }
+ }
+ }
+
+ /**
+ * A subclass of WindowlessWindowManager that provides insets to its viewroots.
+ */
+ public class SysUiWindowManager extends WindowlessWindowManager {
+ final int mDisplayId;
+ ContainerWindow mContainerWindow;
+ public SysUiWindowManager(int displayId, Context ctx, SurfaceControl rootSurface,
+ ContainerWindow container) {
+ super(ctx.getResources().getConfiguration(), rootSurface, null /* hostInputToken */);
+ mContainerWindow = container;
+ mDisplayId = displayId;
+ }
+
+ @Override
+ public int relayout(IWindow window, int seq, WindowManager.LayoutParams attrs,
+ int requestedWidth, int requestedHeight, int viewVisibility, int flags,
+ long frameNumber, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
+ Rect outVisibleInsets, Rect outStableInsets,
+ DisplayCutout.ParcelableWrapper cutout, MergedConfiguration mergedConfiguration,
+ SurfaceControl outSurfaceControl, InsetsState outInsetsState,
+ InsetsSourceControl[] outActiveControls, Point outSurfaceSize,
+ SurfaceControl outBLASTSurfaceControl) {
+ int res = super.relayout(window, seq, attrs, requestedWidth, requestedHeight,
+ viewVisibility, flags, frameNumber, outFrame, outOverscanInsets,
+ outContentInsets, outVisibleInsets, outStableInsets,
+ cutout, mergedConfiguration, outSurfaceControl, outInsetsState,
+ outActiveControls, outSurfaceSize, outBLASTSurfaceControl);
+ if (res != 0) {
+ return res;
+ }
+ DisplayLayout dl = mDisplayController.getDisplayLayout(mDisplayId);
+ outStableInsets.set(dl.stableInsets());
+ return 0;
+ }
+
+ void updateConfiguration(Configuration configuration) {
+ setConfiguration(configuration);
+ }
+
+ SurfaceControl getSurfaceControlForWindow(View rootView) {
+ return getSurfaceControl(rootView);
+ }
+
+ void setTouchableRegionForWindow(View rootView, Region region) {
+ IBinder token = rootView.getWindowToken();
+ if (token == null) {
+ return;
+ }
+ setTouchRegion(token, region);
+ }
+ }
+
+ static class ContainerWindow extends IWindow.Stub {
+ ContainerWindow() {}
+
+ @Override
+ public void resized(Rect frame, Rect contentInsets, Rect visibleInsets, Rect stableInsets,
+ boolean reportDraw, MergedConfiguration newMergedConfiguration, Rect backDropFrame,
+ boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId,
+ DisplayCutout.ParcelableWrapper displayCutout) {}
+
+ @Override
+ public void locationInParentDisplayChanged(Point offset) {}
+
+ @Override
+ public void insetsChanged(InsetsState insetsState) {}
+
+ @Override
+ public void insetsControlChanged(InsetsState insetsState,
+ InsetsSourceControl[] activeControls) {}
+
+ @Override
+ public void showInsets(int types, boolean fromIme) {}
+
+ @Override
+ public void hideInsets(int types, boolean fromIme) {}
+
+ @Override
+ public void moved(int newX, int newY) {}
+
+ @Override
+ public void dispatchAppVisibility(boolean visible) {}
+
+ @Override
+ public void dispatchGetNewSurface() {}
+
+ @Override
+ public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {}
+
+ @Override
+ public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {}
+
+ @Override
+ public void closeSystemDialogs(String reason) {}
+
+ @Override
+ public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
+ float zoom, boolean sync) {}
+
+ @Override
+ public void dispatchWallpaperCommand(String action, int x, int y,
+ int z, Bundle extras, boolean sync) {}
+
+ /* Drag/drop */
+ @Override
+ public void dispatchDragEvent(DragEvent event) {}
+
+ @Override
+ public void updatePointerIcon(float x, float y) {}
+
+ @Override
+ public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
+ int localValue, int localChanges) {}
+
+ @Override
+ public void dispatchWindowShown() {}
+
+ @Override
+ public void requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId) {}
+
+ @Override
+ public void dispatchPointerCaptureChanged(boolean hasCapture) {}
+
+ @Override
+ public void requestScrollCapture(IScrollCaptureController controller) {
+ try {
+ controller.onClientUnavailable();
+ } catch (RemoteException ex) {
+ // ignore
+ }
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TransactionPool.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TransactionPool.java
new file mode 100644
index 000000000000..4c34566b0d98
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TransactionPool.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.common;
+
+import android.util.Pools;
+import android.view.SurfaceControl;
+
+/**
+ * Provides a synchronized pool of {@link SurfaceControl.Transaction}s to minimize allocations.
+ */
+public class TransactionPool {
+ private final Pools.SynchronizedPool<SurfaceControl.Transaction> mTransactionPool =
+ new Pools.SynchronizedPool<>(4);
+
+ public TransactionPool() {
+ }
+
+ /** Gets a transaction from the pool. */
+ public SurfaceControl.Transaction acquire() {
+ SurfaceControl.Transaction t = mTransactionPool.acquire();
+ if (t == null) {
+ return new SurfaceControl.Transaction();
+ }
+ return t;
+ }
+
+ /**
+ * Return a transaction to the pool. DO NOT call {@link SurfaceControl.Transaction#close()} if
+ * returning to pool.
+ */
+ public void release(SurfaceControl.Transaction t) {
+ if (!mTransactionPool.release(t)) {
+ t.close();
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/Android.bp b/libs/WindowManager/Shell/tests/Android.bp
index 78fa45ebdf94..9868879cebb9 100644
--- a/libs/WindowManager/Shell/tests/Android.bp
+++ b/libs/WindowManager/Shell/tests/Android.bp
@@ -36,9 +36,6 @@ android_test {
"libstaticjvmtiagent",
],
- sdk_version: "current",
- platform_apis: true,
-
optimize: {
enabled: false,
},
diff --git a/libs/WindowManager/Shell/tests/src/com/android/wm/shell/tests/WindowManagerShellTest.java b/libs/WindowManager/Shell/tests/src/com/android/wm/shell/WindowManagerShellTest.java
index 376875b143a1..f1ead3c8a441 100644
--- a/libs/WindowManager/Shell/tests/src/com/android/wm/shell/tests/WindowManagerShellTest.java
+++ b/libs/WindowManager/Shell/tests/src/com/android/wm/shell/WindowManagerShellTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,13 +14,11 @@
* limitations under the License.
*/
-package com.android.wm.shell.tests;
+package com.android.wm.shell;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
-import com.android.wm.shell.WindowManagerShell;
-
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/libs/WindowManager/Shell/tests/src/com/android/wm/shell/common/DisplayLayoutTest.java b/libs/WindowManager/Shell/tests/src/com/android/wm/shell/common/DisplayLayoutTest.java
new file mode 100644
index 000000000000..2b5b77e49e3a
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/src/com/android/wm/shell/common/DisplayLayoutTest.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.common;
+
+import static android.content.res.Configuration.UI_MODE_TYPE_NORMAL;
+import static android.view.Surface.ROTATION_0;
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Insets;
+import android.graphics.Rect;
+import android.view.DisplayCutout;
+import android.view.DisplayInfo;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.R;
+
+import org.junit.Test;
+
+@SmallTest
+public class DisplayLayoutTest {
+
+ @Test
+ public void testInsets() {
+ Resources res = createResources(40, 50, false, 30, 40);
+ // Test empty display, no bars or anything
+ DisplayInfo info = createDisplayInfo(1000, 1500, 0, ROTATION_0);
+ DisplayLayout dl = new DisplayLayout(info, res, false, false);
+ assertEquals(new Rect(0, 0, 0, 0), dl.stableInsets());
+ assertEquals(new Rect(0, 0, 0, 0), dl.nonDecorInsets());
+
+ // Test with bars
+ dl = new DisplayLayout(info, res, true, true);
+ assertEquals(new Rect(0, 40, 0, 50), dl.stableInsets());
+ assertEquals(new Rect(0, 0, 0, 50), dl.nonDecorInsets());
+
+ // Test just cutout
+ info = createDisplayInfo(1000, 1500, 60, ROTATION_0);
+ dl = new DisplayLayout(info, res, false, false);
+ assertEquals(new Rect(0, 60, 0, 0), dl.stableInsets());
+ assertEquals(new Rect(0, 60, 0, 0), dl.nonDecorInsets());
+
+ // Test with bars and cutout
+ dl = new DisplayLayout(info, res, true, true);
+ assertEquals(new Rect(0, 60, 0, 50), dl.stableInsets());
+ assertEquals(new Rect(0, 60, 0, 50), dl.nonDecorInsets());
+ }
+
+ @Test
+ public void testRotate() {
+ // Basic rotate utility
+ Rect testParent = new Rect(0, 0, 1000, 600);
+ Rect testInner = new Rect(40, 20, 120, 80);
+ Rect testResult = new Rect(testInner);
+ DisplayLayout.rotateBounds(testResult, testParent, 1);
+ assertEquals(new Rect(20, 880, 80, 960), testResult);
+ testResult.set(testInner);
+ DisplayLayout.rotateBounds(testResult, testParent, 2);
+ assertEquals(new Rect(880, 20, 960, 80), testResult);
+ testResult.set(testInner);
+ DisplayLayout.rotateBounds(testResult, testParent, 3);
+ assertEquals(new Rect(520, 40, 580, 120), testResult);
+
+ Resources res = createResources(40, 50, false, 30, 40);
+ DisplayInfo info = createDisplayInfo(1000, 1500, 60, ROTATION_0);
+ DisplayLayout dl = new DisplayLayout(info, res, true, true);
+ assertEquals(new Rect(0, 60, 0, 50), dl.stableInsets());
+ assertEquals(new Rect(0, 60, 0, 50), dl.nonDecorInsets());
+
+ // Rotate to 90
+ dl.rotateTo(res, ROTATION_90);
+ assertEquals(new Rect(60, 30, 0, 40), dl.stableInsets());
+ assertEquals(new Rect(60, 0, 0, 40), dl.nonDecorInsets());
+
+ // Rotate with moving navbar
+ res = createResources(40, 50, true, 30, 40);
+ dl = new DisplayLayout(info, res, true, true);
+ dl.rotateTo(res, ROTATION_270);
+ assertEquals(new Rect(40, 30, 60, 0), dl.stableInsets());
+ assertEquals(new Rect(40, 0, 60, 0), dl.nonDecorInsets());
+ }
+
+ private Resources createResources(
+ int navLand, int navPort, boolean navMoves, int statusLand, int statusPort) {
+ Configuration cfg = new Configuration();
+ cfg.uiMode = UI_MODE_TYPE_NORMAL;
+ Resources res = mock(Resources.class);
+ doReturn(navLand).when(res).getDimensionPixelSize(
+ R.dimen.navigation_bar_height_landscape_car_mode);
+ doReturn(navPort).when(res).getDimensionPixelSize(R.dimen.navigation_bar_height_car_mode);
+ doReturn(navLand).when(res).getDimensionPixelSize(R.dimen.navigation_bar_width_car_mode);
+ doReturn(navLand).when(res).getDimensionPixelSize(R.dimen.navigation_bar_height_landscape);
+ doReturn(navPort).when(res).getDimensionPixelSize(R.dimen.navigation_bar_height);
+ doReturn(navLand).when(res).getDimensionPixelSize(R.dimen.navigation_bar_width);
+ doReturn(navMoves).when(res).getBoolean(R.bool.config_navBarCanMove);
+ doReturn(statusLand).when(res).getDimensionPixelSize(R.dimen.status_bar_height_landscape);
+ doReturn(statusPort).when(res).getDimensionPixelSize(R.dimen.status_bar_height_portrait);
+ doReturn(cfg).when(res).getConfiguration();
+ return res;
+ }
+
+ private DisplayInfo createDisplayInfo(int width, int height, int cutoutHeight, int rotation) {
+ DisplayInfo info = new DisplayInfo();
+ info.logicalWidth = width;
+ info.logicalHeight = height;
+ info.rotation = rotation;
+ if (cutoutHeight > 0) {
+ info.displayCutout = new DisplayCutout(
+ Insets.of(0, cutoutHeight, 0, 0) /* safeInsets */, null /* boundLeft */,
+ new Rect(width / 2 - cutoutHeight, 0, width / 2 + cutoutHeight,
+ cutoutHeight) /* boundTop */, null /* boundRight */,
+ null /* boundBottom */);
+ } else {
+ info.displayCutout = DisplayCutout.NO_CUTOUT;
+ }
+ info.logicalDensityDpi = 300;
+ return info;
+ }
+}
diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp
index aa34edf487fe..8ab7da5257ab 100644
--- a/libs/androidfw/Android.bp
+++ b/libs/androidfw/Android.bp
@@ -155,6 +155,7 @@ cc_test {
android: {
srcs: [
"tests/BackupData_test.cpp",
+ "tests/BackupHelpers_test.cpp",
"tests/ObbFile_test.cpp",
"tests/PosixUtils_test.cpp",
],
diff --git a/libs/androidfw/BackupHelpers.cpp b/libs/androidfw/BackupHelpers.cpp
index 8bfe2b6a259a..e80e9486c8b2 100644
--- a/libs/androidfw/BackupHelpers.cpp
+++ b/libs/androidfw/BackupHelpers.cpp
@@ -479,7 +479,7 @@ void send_tarfile_chunk(BackupDataWriter* writer, const char* buffer, size_t siz
}
int write_tarfile(const String8& packageName, const String8& domain,
- const String8& rootpath, const String8& filepath, off_t* outSize,
+ const String8& rootpath, const String8& filepath, off64_t* outSize,
BackupDataWriter* writer)
{
// In the output stream everything is stored relative to the root
diff --git a/libs/androidfw/include/androidfw/BackupHelpers.h b/libs/androidfw/include/androidfw/BackupHelpers.h
index 2da247b77c0a..a0fa13662cb9 100644
--- a/libs/androidfw/include/androidfw/BackupHelpers.h
+++ b/libs/androidfw/include/androidfw/BackupHelpers.h
@@ -137,7 +137,7 @@ int back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapsh
char const* const* files, char const* const *keys, int fileCount);
int write_tarfile(const String8& packageName, const String8& domain,
- const String8& rootPath, const String8& filePath, off_t* outSize,
+ const String8& rootPath, const String8& filePath, off64_t* outSize,
BackupDataWriter* outputStream);
class RestoreHelperBase
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index e351a46d633a..e10a7f3f5c61 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -1717,6 +1717,10 @@ struct ResTable_overlayable_policy_header
// The overlay must be signed with the same signature as the actor declared for the target
// resource
ACTOR_SIGNATURE = 0x00000080,
+
+ // The overlay must be signed with the same signature as the reference package declared
+ // in the SystemConfig
+ CONFIG_SIGNATURE = 0x00000100,
};
using PolicyBitmask = uint32_t;
diff --git a/libs/androidfw/tests/BackupHelpers_test.cpp b/libs/androidfw/tests/BackupHelpers_test.cpp
new file mode 100644
index 000000000000..86b7fb361228
--- /dev/null
+++ b/libs/androidfw/tests/BackupHelpers_test.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "BackupHelpers_test"
+#include <androidfw/BackupHelpers.h>
+
+#include <gtest/gtest.h>
+
+#include <fcntl.h>
+#include <utils/String8.h>
+#include <android-base/file.h>
+
+namespace android {
+
+class BackupHelpersTest : public testing::Test {
+protected:
+
+ virtual void SetUp() {
+ }
+ virtual void TearDown() {
+ }
+};
+
+TEST_F(BackupHelpersTest, WriteTarFileWithSizeLessThan2GB) {
+ TemporaryFile tf;
+ // Allocate a 1 KB file.
+ off64_t fileSize = 1024;
+ ASSERT_EQ(0, posix_fallocate64(tf.fd, 0, fileSize));
+ off64_t tarSize = 0;
+ int err = write_tarfile(/* packageName */ String8("test-pkg"), /* domain */ String8(""), /* rootpath */ String8(""), /* filePath */ String8(tf.path), /* outSize */ &tarSize, /* writer */ NULL);
+ ASSERT_EQ(err, 0);
+ // Returned tarSize includes 512 B for the header.
+ off64_t expectedTarSize = fileSize + 512;
+ ASSERT_EQ(tarSize, expectedTarSize);
+}
+
+TEST_F(BackupHelpersTest, WriteTarFileWithSizeGreaterThan2GB) {
+ TemporaryFile tf;
+ // Allocate a 2 GB file.
+ off64_t fileSize = 2ll * 1024ll * 1024ll * 1024ll + 512ll;
+ ASSERT_EQ(0, posix_fallocate64(tf.fd, 0, fileSize));
+ off64_t tarSize = 0;
+ int err = write_tarfile(/* packageName */ String8("test-pkg"), /* domain */ String8(""), /* rootpath */ String8(""), /* filePath */ String8(tf.path), /* outSize */ &tarSize, /* writer */ NULL);
+ ASSERT_EQ(err, 0);
+ // Returned tarSize includes 512 B for the header.
+ off64_t expectedTarSize = fileSize + 512;
+ ASSERT_EQ(tarSize, expectedTarSize);
+}
+}
+
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index aa842ff6a7b7..9ae5ad97ed36 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -53,8 +53,6 @@ cc_defaults {
host: {
include_dirs: [
"external/vulkan-headers/include",
- "frameworks/native/libs/math/include",
- "frameworks/native/libs/ui/include",
],
cflags: [
"-Wno-unused-variable",
@@ -71,6 +69,10 @@ cc_defaults {
"libminikin",
],
+ static_libs: [
+ "libui-types",
+ ],
+
target: {
android: {
shared_libs: [
@@ -83,7 +85,6 @@ cc_defaults {
"libGLESv2",
"libGLESv3",
"libvulkan",
- "libui",
"libnativedisplay",
"libnativewindow",
"libprotobuf-cpp-lite",
@@ -152,6 +153,45 @@ cc_defaults {
}
// ------------------------
+// framework-graphics jar
+// ------------------------
+
+java_sdk_library {
+ name: "framework-graphics",
+ defaults: ["framework-module-defaults"],
+ visibility: [
+ "//frameworks/base", // Framework
+ ],
+
+ srcs: [
+ ":framework-graphics-srcs",
+ ],
+
+ permitted_packages: [
+ "android.graphics",
+ ],
+
+ // TODO: once framework-graphics is officially part of the
+ // UI-rendering module this line would no longer be
+ // needed.
+ installable: true,
+
+ // Disable api_lint that the defaults enable
+ // TODO: enable this
+ api_lint: {
+ enabled: false,
+ },
+}
+
+filegroup {
+ name: "framework-graphics-srcs",
+ srcs: [
+ "apex/java/**/*.java",
+ ],
+ path: "apex/java"
+}
+
+// ------------------------
// APEX
// ------------------------
@@ -346,6 +386,7 @@ cc_defaults {
"libstatspull",
"libstatssocket",
"libpdfium",
+ "libbinder_ndk",
],
static_libs: [
"libgif",
@@ -457,6 +498,7 @@ cc_defaults {
"service/GraphicsStatsService.cpp",
"thread/CommonPool.cpp",
"utils/GLUtils.cpp",
+ "utils/NdkUtils.cpp",
"utils/StringUtils.cpp",
"AutoBackendTextureRelease.cpp",
"DeferredLayerUpdater.cpp",
@@ -499,6 +541,11 @@ cc_library {
"android_graphics_jni",
],
export_header_lib_headers: ["android_graphics_apex_headers"],
+ target: {
+ android: {
+ version_script: "libhwui.map.txt",
+ }
+ },
}
cc_library_static {
@@ -516,6 +563,7 @@ cc_defaults {
android: {
shared_libs: [
"libgui",
+ "libui",
],
}
},
diff --git a/libs/hwui/AnimationContext.h b/libs/hwui/AnimationContext.h
index 74d5e79c0b77..f8a2072ffbdb 100644
--- a/libs/hwui/AnimationContext.h
+++ b/libs/hwui/AnimationContext.h
@@ -77,8 +77,8 @@ class AnimationContext {
PREVENT_COPY_AND_ASSIGN(AnimationContext);
public:
- ANDROID_API explicit AnimationContext(renderthread::TimeLord& clock);
- ANDROID_API virtual ~AnimationContext();
+ explicit AnimationContext(renderthread::TimeLord& clock);
+ virtual ~AnimationContext();
nsecs_t frameTimeMs() { return mFrameTimeMs; }
bool hasAnimations() {
@@ -87,22 +87,22 @@ public:
// Will always add to the next frame list, which is swapped when
// startFrame() is called
- ANDROID_API void addAnimatingRenderNode(RenderNode& node);
+ void addAnimatingRenderNode(RenderNode& node);
// Marks the start of a frame, which will update the frame time and move all
// next frame animations into the current frame
- ANDROID_API virtual void startFrame(TreeInfo::TraversalMode mode);
+ virtual void startFrame(TreeInfo::TraversalMode mode);
// Runs any animations still left in mCurrentFrameAnimations that were not run
// as part of the standard RenderNode:prepareTree pass.
- ANDROID_API virtual void runRemainingAnimations(TreeInfo& info);
+ virtual void runRemainingAnimations(TreeInfo& info);
- ANDROID_API virtual void callOnFinished(BaseRenderNodeAnimator* animator,
+ virtual void callOnFinished(BaseRenderNodeAnimator* animator,
AnimationListener* listener);
- ANDROID_API virtual void destroy();
+ virtual void destroy();
- ANDROID_API virtual void pauseAnimators() {}
+ virtual void pauseAnimators() {}
private:
friend class AnimationHandle;
diff --git a/libs/hwui/Animator.h b/libs/hwui/Animator.h
index ed7b6eb1cf4a..3c9f1ea1b6e3 100644
--- a/libs/hwui/Animator.h
+++ b/libs/hwui/Animator.h
@@ -39,10 +39,10 @@ class RenderProperties;
class AnimationListener : public VirtualLightRefBase {
public:
- ANDROID_API virtual void onAnimationFinished(BaseRenderNodeAnimator*) = 0;
+ virtual void onAnimationFinished(BaseRenderNodeAnimator*) = 0;
protected:
- ANDROID_API virtual ~AnimationListener() {}
+ virtual ~AnimationListener() {}
};
enum class RepeatMode {
@@ -55,34 +55,34 @@ class BaseRenderNodeAnimator : public VirtualLightRefBase {
PREVENT_COPY_AND_ASSIGN(BaseRenderNodeAnimator);
public:
- ANDROID_API void setStartValue(float value);
- ANDROID_API void setInterpolator(Interpolator* interpolator);
- ANDROID_API void setDuration(nsecs_t durationInMs);
- ANDROID_API nsecs_t duration() { return mDuration; }
- ANDROID_API void setStartDelay(nsecs_t startDelayInMs);
- ANDROID_API nsecs_t startDelay() { return mStartDelay; }
- ANDROID_API void setListener(AnimationListener* listener) { mListener = listener; }
+ void setStartValue(float value);
+ void setInterpolator(Interpolator* interpolator);
+ void setDuration(nsecs_t durationInMs);
+ nsecs_t duration() { return mDuration; }
+ void setStartDelay(nsecs_t startDelayInMs);
+ nsecs_t startDelay() { return mStartDelay; }
+ void setListener(AnimationListener* listener) { mListener = listener; }
AnimationListener* listener() { return mListener.get(); }
- ANDROID_API void setAllowRunningAsync(bool mayRunAsync) { mMayRunAsync = mayRunAsync; }
+ void setAllowRunningAsync(bool mayRunAsync) { mMayRunAsync = mayRunAsync; }
bool mayRunAsync() { return mMayRunAsync; }
- ANDROID_API void start();
- ANDROID_API virtual void reset();
- ANDROID_API void reverse();
+ void start();
+ virtual void reset();
+ void reverse();
// Terminates the animation at its current progress.
- ANDROID_API void cancel();
+ void cancel();
// Terminates the animation and skip to the end of the animation.
- ANDROID_API virtual void end();
+ virtual void end();
void attach(RenderNode* target);
virtual void onAttached() {}
void detach() { mTarget = nullptr; }
- ANDROID_API void pushStaging(AnimationContext& context);
- ANDROID_API bool animate(AnimationContext& context);
+ void pushStaging(AnimationContext& context);
+ bool animate(AnimationContext& context);
// Returns the remaining time in ms for the animation. Note this should only be called during
// an animation on RenderThread.
- ANDROID_API nsecs_t getRemainingPlayTime();
+ nsecs_t getRemainingPlayTime();
bool isRunning() {
return mPlayState == PlayState::Running || mPlayState == PlayState::Reversing;
@@ -90,7 +90,7 @@ public:
bool isFinished() { return mPlayState == PlayState::Finished; }
float finalValue() { return mFinalValue; }
- ANDROID_API virtual uint32_t dirtyMask() = 0;
+ virtual uint32_t dirtyMask() = 0;
void forceEndNow(AnimationContext& context);
RenderNode* target() { return mTarget; }
@@ -196,9 +196,9 @@ public:
ALPHA,
};
- ANDROID_API RenderPropertyAnimator(RenderProperty property, float finalValue);
+ RenderPropertyAnimator(RenderProperty property, float finalValue);
- ANDROID_API virtual uint32_t dirtyMask();
+ virtual uint32_t dirtyMask();
protected:
virtual float getValue(RenderNode* target) const override;
@@ -221,10 +221,10 @@ private:
class CanvasPropertyPrimitiveAnimator : public BaseRenderNodeAnimator {
public:
- ANDROID_API CanvasPropertyPrimitiveAnimator(CanvasPropertyPrimitive* property,
+ CanvasPropertyPrimitiveAnimator(CanvasPropertyPrimitive* property,
float finalValue);
- ANDROID_API virtual uint32_t dirtyMask();
+ virtual uint32_t dirtyMask();
protected:
virtual float getValue(RenderNode* target) const override;
@@ -241,10 +241,10 @@ public:
ALPHA,
};
- ANDROID_API CanvasPropertyPaintAnimator(CanvasPropertyPaint* property, PaintField field,
+ CanvasPropertyPaintAnimator(CanvasPropertyPaint* property, PaintField field,
float finalValue);
- ANDROID_API virtual uint32_t dirtyMask();
+ virtual uint32_t dirtyMask();
protected:
virtual float getValue(RenderNode* target) const override;
@@ -257,9 +257,9 @@ private:
class RevealAnimator : public BaseRenderNodeAnimator {
public:
- ANDROID_API RevealAnimator(int centerX, int centerY, float startValue, float finalValue);
+ RevealAnimator(int centerX, int centerY, float startValue, float finalValue);
- ANDROID_API virtual uint32_t dirtyMask();
+ virtual uint32_t dirtyMask();
protected:
virtual float getValue(RenderNode* target) const override;
diff --git a/libs/hwui/AnimatorManager.h b/libs/hwui/AnimatorManager.h
index 9575391a8b3f..a0df01d5962c 100644
--- a/libs/hwui/AnimatorManager.h
+++ b/libs/hwui/AnimatorManager.h
@@ -54,7 +54,7 @@ public:
void animateNoDamage(TreeInfo& info);
// Hard-ends all animators. May only be called on the UI thread.
- ANDROID_API void endAllStagingAnimators();
+ void endAllStagingAnimators();
// Hard-ends all animators that have been pushed. Used for cleanup if
// the ActivityContext is being destroyed
diff --git a/libs/hwui/AutoBackendTextureRelease.cpp b/libs/hwui/AutoBackendTextureRelease.cpp
index 72747e8fa543..33264d5d5c86 100644
--- a/libs/hwui/AutoBackendTextureRelease.cpp
+++ b/libs/hwui/AutoBackendTextureRelease.cpp
@@ -25,7 +25,8 @@ using namespace android::uirenderer::renderthread;
namespace android {
namespace uirenderer {
-AutoBackendTextureRelease::AutoBackendTextureRelease(GrContext* context, AHardwareBuffer* buffer) {
+AutoBackendTextureRelease::AutoBackendTextureRelease(GrDirectContext* context,
+ AHardwareBuffer* buffer) {
AHardwareBuffer_Desc desc;
AHardwareBuffer_describe(buffer, &desc);
bool createProtectedImage = 0 != (desc.usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT);
@@ -67,8 +68,9 @@ static void releaseProc(SkImage::ReleaseContext releaseContext) {
textureRelease->unref(false);
}
-void AutoBackendTextureRelease::makeImage(AHardwareBuffer* buffer, android_dataspace dataspace,
- GrContext* context) {
+void AutoBackendTextureRelease::makeImage(AHardwareBuffer* buffer,
+ android_dataspace dataspace,
+ GrDirectContext* context) {
AHardwareBuffer_Desc desc;
AHardwareBuffer_describe(buffer, &desc);
SkColorType colorType = GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(desc.format);
@@ -81,7 +83,7 @@ void AutoBackendTextureRelease::makeImage(AHardwareBuffer* buffer, android_datas
}
}
-void AutoBackendTextureRelease::newBufferContent(GrContext* context) {
+void AutoBackendTextureRelease::newBufferContent(GrDirectContext* context) {
if (mBackendTexture.isValid()) {
mUpdateProc(mImageCtx, context);
}
diff --git a/libs/hwui/AutoBackendTextureRelease.h b/libs/hwui/AutoBackendTextureRelease.h
index acdd63cb7921..06f51fcd1105 100644
--- a/libs/hwui/AutoBackendTextureRelease.h
+++ b/libs/hwui/AutoBackendTextureRelease.h
@@ -31,7 +31,8 @@ namespace uirenderer {
*/
class AutoBackendTextureRelease final {
public:
- AutoBackendTextureRelease(GrContext* context, AHardwareBuffer* buffer);
+ AutoBackendTextureRelease(GrDirectContext* context,
+ AHardwareBuffer* buffer);
const GrBackendTexture& getTexture() const { return mBackendTexture; }
@@ -42,9 +43,11 @@ public:
inline sk_sp<SkImage> getImage() const { return mImage; }
- void makeImage(AHardwareBuffer* buffer, android_dataspace dataspace, GrContext* context);
+ void makeImage(AHardwareBuffer* buffer,
+ android_dataspace dataspace,
+ GrDirectContext* context);
- void newBufferContent(GrContext* context);
+ void newBufferContent(GrDirectContext* context);
private:
// The only way to invoke dtor is with unref, when mUsageCount is 0.
diff --git a/libs/hwui/CanvasTransform.cpp b/libs/hwui/CanvasTransform.cpp
index 8c37d73366c2..9d03ce5252a3 100644
--- a/libs/hwui/CanvasTransform.cpp
+++ b/libs/hwui/CanvasTransform.cpp
@@ -22,7 +22,6 @@
#include <SkGradientShader.h>
#include <SkPaint.h>
#include <SkShader.h>
-#include <ui/ColorSpace.h>
#include <algorithm>
#include <cmath>
diff --git a/libs/hwui/ColorMode.h b/libs/hwui/ColorMode.h
new file mode 100644
index 000000000000..6d387f9ef43d
--- /dev/null
+++ b/libs/hwui/ColorMode.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+namespace android::uirenderer {
+
+// Must match the constants in ActivityInfo.java
+enum class ColorMode {
+ // SRGB means HWUI will produce buffer in SRGB color space.
+ Default = 0,
+ // WideColorGamut selects the most optimal colorspace & format for the device's display
+ // Most commonly DisplayP3 + RGBA_8888 currently.
+ WideColorGamut = 1,
+ // HDR Rec2020 + F16
+ Hdr = 2,
+ // HDR Rec2020 + 1010102
+ Hdr10 = 3,
+};
+
+} // namespace android::uirenderer
diff --git a/libs/hwui/DamageAccumulator.h b/libs/hwui/DamageAccumulator.h
index 030a20f31c42..2faa9d012d66 100644
--- a/libs/hwui/DamageAccumulator.h
+++ b/libs/hwui/DamageAccumulator.h
@@ -58,7 +58,7 @@ public:
// Returns the current dirty area, *NOT* transformed by pushed transforms
void peekAtDirty(SkRect* dest) const;
- ANDROID_API void computeCurrentTransform(Matrix4* outMatrix) const;
+ void computeCurrentTransform(Matrix4* outMatrix) const;
void finish(SkRect* totalDirty);
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index 67d8c07e61de..6589dbd50cf7 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -189,7 +189,7 @@ void DeferredLayerUpdater::detachSurfaceTexture() {
sk_sp<SkImage> DeferredLayerUpdater::ImageSlot::createIfNeeded(AHardwareBuffer* buffer,
android_dataspace dataspace,
bool forceCreate,
- GrContext* context) {
+ GrDirectContext* context) {
if (!mTextureRelease || !mTextureRelease->getImage().get() || dataspace != mDataspace ||
forceCreate || mBuffer != buffer) {
if (buffer != mBuffer) {
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index c44c0d537fa7..6731e9c428d6 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -44,11 +44,11 @@ class DeferredLayerUpdater : public VirtualLightRefBase, public IGpuContextCallb
public:
// Note that DeferredLayerUpdater assumes it is taking ownership of the layer
// and will not call incrementRef on it as a result.
- ANDROID_API explicit DeferredLayerUpdater(RenderState& renderState);
+ explicit DeferredLayerUpdater(RenderState& renderState);
- ANDROID_API ~DeferredLayerUpdater();
+ ~DeferredLayerUpdater();
- ANDROID_API bool setSize(int width, int height) {
+ bool setSize(int width, int height) {
if (mWidth != width || mHeight != height) {
mWidth = width;
mHeight = height;
@@ -60,7 +60,7 @@ public:
int getWidth() { return mWidth; }
int getHeight() { return mHeight; }
- ANDROID_API bool setBlend(bool blend) {
+ bool setBlend(bool blend) {
if (blend != mBlend) {
mBlend = blend;
return true;
@@ -68,18 +68,18 @@ public:
return false;
}
- ANDROID_API void setSurfaceTexture(AutoTextureRelease&& consumer);
+ void setSurfaceTexture(AutoTextureRelease&& consumer);
- ANDROID_API void updateTexImage() { mUpdateTexImage = true; }
+ void updateTexImage() { mUpdateTexImage = true; }
- ANDROID_API void setTransform(const SkMatrix* matrix) {
+ void setTransform(const SkMatrix* matrix) {
delete mTransform;
mTransform = matrix ? new SkMatrix(*matrix) : nullptr;
}
SkMatrix* getTransform() { return mTransform; }
- ANDROID_API void setPaint(const SkPaint* paint);
+ void setPaint(const SkPaint* paint);
void apply();
@@ -106,7 +106,7 @@ private:
~ImageSlot() { clear(); }
sk_sp<SkImage> createIfNeeded(AHardwareBuffer* buffer, android_dataspace dataspace,
- bool forceCreate, GrContext* context);
+ bool forceCreate, GrDirectContext* context);
private:
void clear();
diff --git a/libs/hwui/DeviceInfo.cpp b/libs/hwui/DeviceInfo.cpp
index c24224cbbd67..07594715a84c 100644
--- a/libs/hwui/DeviceInfo.cpp
+++ b/libs/hwui/DeviceInfo.cpp
@@ -15,6 +15,8 @@
*/
#include <DeviceInfo.h>
+#include <android/hardware_buffer.h>
+#include <apex/display.h>
#include <log/log.h>
#include <utils/Errors.h>
@@ -30,14 +32,47 @@ DeviceInfo* DeviceInfo::get() {
DeviceInfo::DeviceInfo() {
#if HWUI_NULL_GPU
- mMaxTextureSize = NULL_GPU_MAX_TEXTURE_SIZE;
+ mMaxTextureSize = NULL_GPU_MAX_TEXTURE_SIZE;
#else
- mMaxTextureSize = -1;
+ mMaxTextureSize = -1;
#endif
- updateDisplayInfo();
}
-DeviceInfo::~DeviceInfo() {
- ADisplay_release(mDisplays);
+
+void DeviceInfo::updateDisplayInfo() {
+ if (Properties::isolatedProcess) {
+ return;
+ }
+
+ ADisplay** displays;
+ int size = ADisplay_acquirePhysicalDisplays(&displays);
+
+ if (size <= 0) {
+ LOG_ALWAYS_FATAL("Failed to acquire physical displays for WCG support!");
+ }
+
+ for (int i = 0; i < size; ++i) {
+ // Pick the first internal display for querying the display type
+ // In practice this is controlled by a sysprop so it doesn't really
+ // matter which display we use.
+ if (ADisplay_getDisplayType(displays[i]) == DISPLAY_TYPE_INTERNAL) {
+ // We get the dataspace from DisplayManager already. Allocate space
+ // for the result here but we don't actually care about using it.
+ ADataSpace dataspace;
+ AHardwareBuffer_Format pixelFormat;
+ ADisplay_getPreferredWideColorFormat(displays[i], &dataspace, &pixelFormat);
+
+ if (pixelFormat == AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM) {
+ mWideColorType = SkColorType::kN32_SkColorType;
+ } else if (pixelFormat == AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT) {
+ mWideColorType = SkColorType::kRGBA_F16_SkColorType;
+ } else {
+ LOG_ALWAYS_FATAL("Unreachable: unsupported pixel format: %d", pixelFormat);
+ }
+ ADisplay_release(displays);
+ return;
+ }
+ }
+ LOG_ALWAYS_FATAL("Failed to find a valid physical display for WCG support!");
}
int DeviceInfo::maxTextureSize() const {
@@ -49,75 +84,29 @@ void DeviceInfo::setMaxTextureSize(int maxTextureSize) {
DeviceInfo::get()->mMaxTextureSize = maxTextureSize;
}
+void DeviceInfo::setWideColorDataspace(ADataSpace dataspace) {
+ switch (dataspace) {
+ case ADATASPACE_DISPLAY_P3:
+ get()->mWideColorSpace =
+ SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kDisplayP3);
+ break;
+ case ADATASPACE_SCRGB:
+ get()->mWideColorSpace = SkColorSpace::MakeSRGB();
+ break;
+ case ADATASPACE_SRGB:
+ // when sRGB is returned, it means wide color gamut is not supported.
+ get()->mWideColorSpace = SkColorSpace::MakeSRGB();
+ break;
+ default:
+ LOG_ALWAYS_FATAL("Unreachable: unsupported wide color space.");
+ }
+}
+
void DeviceInfo::onRefreshRateChanged(int64_t vsyncPeriod) {
mVsyncPeriod = vsyncPeriod;
}
-void DeviceInfo::updateDisplayInfo() {
- if (Properties::isolatedProcess) {
- return;
- }
-
- if (mCurrentConfig == nullptr) {
- mDisplaysSize = ADisplay_acquirePhysicalDisplays(&mDisplays);
- LOG_ALWAYS_FATAL_IF(mDisplays == nullptr || mDisplaysSize <= 0,
- "Failed to get physical displays: no connected display: %d!", mDisplaysSize);
- for (size_t i = 0; i < mDisplaysSize; i++) {
- ADisplayType type = ADisplay_getDisplayType(mDisplays[i]);
- if (type == ADisplayType::DISPLAY_TYPE_INTERNAL) {
- mPhysicalDisplayIndex = i;
- break;
- }
- }
- LOG_ALWAYS_FATAL_IF(mPhysicalDisplayIndex < 0, "Failed to find a connected physical display!");
-
-
- // Since we now just got the primary display for the first time, then
- // store the primary display metadata here.
- ADisplay* primaryDisplay = mDisplays[mPhysicalDisplayIndex];
- mMaxRefreshRate = ADisplay_getMaxSupportedFps(primaryDisplay);
- ADataSpace dataspace;
- AHardwareBuffer_Format format;
- ADisplay_getPreferredWideColorFormat(primaryDisplay, &dataspace, &format);
- switch (dataspace) {
- case ADATASPACE_DISPLAY_P3:
- mWideColorSpace =
- SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kDCIP3);
- break;
- case ADATASPACE_SCRGB:
- mWideColorSpace = SkColorSpace::MakeSRGB();
- break;
- case ADATASPACE_SRGB:
- // when sRGB is returned, it means wide color gamut is not supported.
- mWideColorSpace = SkColorSpace::MakeSRGB();
- break;
- default:
- LOG_ALWAYS_FATAL("Unreachable: unsupported wide color space.");
- }
- switch (format) {
- case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
- mWideColorType = SkColorType::kN32_SkColorType;
- break;
- case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
- mWideColorType = SkColorType::kRGBA_F16_SkColorType;
- break;
- default:
- LOG_ALWAYS_FATAL("Unreachable: unsupported pixel format.");
- }
- }
- // This method may have been called when the display config changed, so
- // sync with the current configuration.
- ADisplay* primaryDisplay = mDisplays[mPhysicalDisplayIndex];
- status_t status = ADisplay_getCurrentConfig(primaryDisplay, &mCurrentConfig);
- LOG_ALWAYS_FATAL_IF(status, "Failed to get display config, error %d", status);
-
- mWidth = ADisplayConfig_getWidth(mCurrentConfig);
- mHeight = ADisplayConfig_getHeight(mCurrentConfig);
- mDensity = ADisplayConfig_getDensity(mCurrentConfig);
- mVsyncPeriod = static_cast<int64_t>(1000000000 / ADisplayConfig_getFps(mCurrentConfig));
- mCompositorOffset = ADisplayConfig_getCompositorOffsetNanos(mCurrentConfig);
- mAppOffset = ADisplayConfig_getAppVsyncOffsetNanos(mCurrentConfig);
-}
+std::atomic<float> DeviceInfo::sDensity = 2.0;
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/DeviceInfo.h b/libs/hwui/DeviceInfo.h
index 16a22f4706f5..27be62269959 100644
--- a/libs/hwui/DeviceInfo.h
+++ b/libs/hwui/DeviceInfo.h
@@ -16,8 +16,10 @@
#ifndef DEVICEINFO_H
#define DEVICEINFO_H
-#include <apex/display.h>
#include <SkImageInfo.h>
+#include <android/data_space.h>
+
+#include <mutex>
#include "utils/Macros.h"
@@ -36,16 +38,37 @@ public:
static float getMaxRefreshRate() { return get()->mMaxRefreshRate; }
static int32_t getWidth() { return get()->mWidth; }
static int32_t getHeight() { return get()->mHeight; }
- static float getDensity() { return get()->mDensity; }
+ // Gets the density in density-independent pixels
+ static float getDensity() { return sDensity.load(); }
static int64_t getVsyncPeriod() { return get()->mVsyncPeriod; }
- static int64_t getCompositorOffset() { return get()->mCompositorOffset; }
- static int64_t getAppOffset() { return get()->mAppOffset; }
+ static int64_t getCompositorOffset() { return get()->getCompositorOffsetInternal(); }
+ static int64_t getAppOffset() { return get()->mAppVsyncOffsetNanos; }
+ // Sets the density in density-independent pixels
+ static void setDensity(float density) { sDensity.store(density); }
+ static void setMaxRefreshRate(float refreshRate) { get()->mMaxRefreshRate = refreshRate; }
+ static void setWidth(int32_t width) { get()->mWidth = width; }
+ static void setHeight(int32_t height) { get()->mHeight = height; }
+ static void setRefreshRate(float refreshRate) {
+ get()->mVsyncPeriod = static_cast<int64_t>(1000000000 / refreshRate);
+ }
+ static void setPresentationDeadlineNanos(int64_t deadlineNanos) {
+ get()->mPresentationDeadlineNanos = deadlineNanos;
+ }
+ static void setAppVsyncOffsetNanos(int64_t offsetNanos) {
+ get()->mAppVsyncOffsetNanos = offsetNanos;
+ }
+ static void setWideColorDataspace(ADataSpace dataspace);
// this value is only valid after the GPU has been initialized and there is a valid graphics
// context or if you are using the HWUI_NULL_GPU
int maxTextureSize() const;
sk_sp<SkColorSpace> getWideColorSpace() const { return mWideColorSpace; }
- SkColorType getWideColorType() const { return mWideColorType; }
+ SkColorType getWideColorType() {
+ static std::once_flag kFlag;
+ // lazily update display info from SF here, so that the call is performed by RenderThread.
+ std::call_once(kFlag, [&, this]() { updateDisplayInfo(); });
+ return mWideColorType;
+ }
// This method should be called whenever the display refresh rate changes.
void onRefreshRateChanged(int64_t vsyncPeriod);
@@ -54,24 +77,32 @@ private:
friend class renderthread::RenderThread;
static void setMaxTextureSize(int maxTextureSize);
void updateDisplayInfo();
+ int64_t getCompositorOffsetInternal() const {
+ // Assume that SF takes around a millisecond to latch buffers after
+ // waking up
+ return mVsyncPeriod - (mPresentationDeadlineNanos - 1000000);
+ }
DeviceInfo();
- ~DeviceInfo();
+ ~DeviceInfo() = default;
int mMaxTextureSize;
sk_sp<SkColorSpace> mWideColorSpace = SkColorSpace::MakeSRGB();
SkColorType mWideColorType = SkColorType::kN32_SkColorType;
- ADisplayConfig* mCurrentConfig = nullptr;
- ADisplay** mDisplays = nullptr;
int mDisplaysSize = 0;
int mPhysicalDisplayIndex = -1;
float mMaxRefreshRate = 60.0;
int32_t mWidth = 1080;
int32_t mHeight = 1920;
- float mDensity = 2.0;
int64_t mVsyncPeriod = 16666666;
- int64_t mCompositorOffset = 0;
- int64_t mAppOffset = 0;
+ // Magically corresponds with an sf offset of 0 for a sane default.
+ int64_t mPresentationDeadlineNanos = 17666666;
+ int64_t mAppVsyncOffsetNanos = 0;
+
+ // Density is not retrieved from the ADisplay apis, so this may potentially
+ // be called on multiple threads.
+ // Unit is density-independent pixels
+ static std::atomic<float> sDensity;
};
} /* namespace uirenderer */
diff --git a/libs/hwui/FrameInfo.h b/libs/hwui/FrameInfo.h
index 51674fbd557e..dc30617009e7 100644
--- a/libs/hwui/FrameInfo.h
+++ b/libs/hwui/FrameInfo.h
@@ -69,7 +69,7 @@ enum {
};
};
-class ANDROID_API UiFrameInfoBuilder {
+class UiFrameInfoBuilder {
public:
explicit UiFrameInfoBuilder(int64_t* buffer) : mBuffer(buffer) {
memset(mBuffer, 0, UI_THREAD_FRAME_INFO_SIZE * sizeof(int64_t));
diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp
index a3d552faeb0a..87244427a719 100644
--- a/libs/hwui/HardwareBitmapUploader.cpp
+++ b/libs/hwui/HardwareBitmapUploader.cpp
@@ -16,24 +16,27 @@
#include "HardwareBitmapUploader.h"
-#include "hwui/Bitmap.h"
-#include "renderthread/EglManager.h"
-#include "renderthread/VulkanManager.h"
-#include "thread/ThreadBase.h"
-#include "utils/TimeUtils.h"
-
+#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <GLES3/gl3.h>
-#include <GrContext.h>
+#include <GrDirectContext.h>
#include <SkCanvas.h>
#include <SkImage.h>
#include <utils/GLUtils.h>
+#include <utils/NdkUtils.h>
#include <utils/Trace.h>
#include <utils/TraceUtils.h>
+
#include <thread>
+#include "hwui/Bitmap.h"
+#include "renderthread/EglManager.h"
+#include "renderthread/VulkanManager.h"
+#include "thread/ThreadBase.h"
+#include "utils/TimeUtils.h"
+
namespace android::uirenderer {
class AHBUploader;
@@ -42,7 +45,7 @@ class AHBUploader;
static sp<AHBUploader> sUploader = nullptr;
struct FormatInfo {
- PixelFormat pixelFormat;
+ AHardwareBuffer_Format bufferFormat;
GLint format, type;
VkFormat vkFormat;
bool isSupported = false;
@@ -71,10 +74,10 @@ public:
}
bool uploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format,
- sp<GraphicBuffer> graphicBuffer) {
+ AHardwareBuffer* ahb) {
ATRACE_CALL();
beginUpload();
- bool result = onUploadHardwareBitmap(bitmap, format, graphicBuffer);
+ bool result = onUploadHardwareBitmap(bitmap, format, ahb);
endUpload();
return result;
}
@@ -93,7 +96,7 @@ private:
virtual void onDestroy() = 0;
virtual bool onUploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format,
- sp<GraphicBuffer> graphicBuffer) = 0;
+ AHardwareBuffer* ahb) = 0;
virtual void onBeginUpload() = 0;
bool shouldTimeOutLocked() {
@@ -165,16 +168,16 @@ private:
}
bool onUploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format,
- sp<GraphicBuffer> graphicBuffer) override {
+ AHardwareBuffer* ahb) override {
ATRACE_CALL();
EGLDisplay display = getUploadEglDisplay();
LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY, "Failed to get EGL_DEFAULT_DISPLAY! err=%s",
uirenderer::renderthread::EglManager::eglErrorString());
- // We use an EGLImage to access the content of the GraphicBuffer
+ // We use an EGLImage to access the content of the buffer
// The EGL image is later bound to a 2D texture
- EGLClientBuffer clientBuffer = (EGLClientBuffer)graphicBuffer->getNativeBuffer();
+ const EGLClientBuffer clientBuffer = eglGetNativeClientBufferANDROID(ahb);
AutoEglImage autoImage(display, clientBuffer);
if (autoImage.image == EGL_NO_IMAGE_KHR) {
ALOGW("Could not create EGL image, err =%s",
@@ -272,17 +275,17 @@ private:
}
bool onUploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format,
- sp<GraphicBuffer> graphicBuffer) override {
+ AHardwareBuffer* ahb) override {
ATRACE_CALL();
std::lock_guard _lock{mLock};
- sk_sp<SkImage> image = SkImage::MakeFromAHardwareBufferWithData(mGrContext.get(),
- bitmap.pixmap(), reinterpret_cast<AHardwareBuffer*>(graphicBuffer.get()));
+ sk_sp<SkImage> image =
+ SkImage::MakeFromAHardwareBufferWithData(mGrContext.get(), bitmap.pixmap(), ahb);
return (image.get() != nullptr);
}
- sk_sp<GrContext> mGrContext;
+ sk_sp<GrDirectContext> mGrContext;
renderthread::VulkanManager mVulkanManager;
std::mutex mVkLock;
};
@@ -294,13 +297,17 @@ bool HardwareBitmapUploader::hasFP16Support() {
// Gralloc shouldn't let us create a USAGE_HW_TEXTURE if GLES is unable to consume it, so
// we don't need to double-check the GLES version/extension.
std::call_once(sOnce, []() {
- sp<GraphicBuffer> buffer = new GraphicBuffer(1, 1, PIXEL_FORMAT_RGBA_FP16,
- GraphicBuffer::USAGE_HW_TEXTURE |
- GraphicBuffer::USAGE_SW_WRITE_NEVER |
- GraphicBuffer::USAGE_SW_READ_NEVER,
- "tempFp16Buffer");
- status_t error = buffer->initCheck();
- hasFP16Support = !error;
+ AHardwareBuffer_Desc desc = {
+ .width = 1,
+ .height = 1,
+ .layers = 1,
+ .format = AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT,
+ .usage = AHARDWAREBUFFER_USAGE_CPU_READ_NEVER |
+ AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER |
+ AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE,
+ };
+ UniqueAHardwareBuffer buffer = allocateAHardwareBuffer(desc);
+ hasFP16Support = buffer != nullptr;
});
return hasFP16Support;
@@ -314,7 +321,7 @@ static FormatInfo determineFormat(const SkBitmap& skBitmap, bool usingGL) {
[[fallthrough]];
// ARGB_4444 is upconverted to RGBA_8888
case kARGB_4444_SkColorType:
- formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_8888;
+ formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
formatInfo.format = GL_RGBA;
formatInfo.type = GL_UNSIGNED_BYTE;
formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
@@ -323,25 +330,25 @@ static FormatInfo determineFormat(const SkBitmap& skBitmap, bool usingGL) {
formatInfo.isSupported = HardwareBitmapUploader::hasFP16Support();
if (formatInfo.isSupported) {
formatInfo.type = GL_HALF_FLOAT;
- formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_FP16;
+ formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT;
formatInfo.vkFormat = VK_FORMAT_R16G16B16A16_SFLOAT;
} else {
formatInfo.type = GL_UNSIGNED_BYTE;
- formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_8888;
+ formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
}
formatInfo.format = GL_RGBA;
break;
case kRGB_565_SkColorType:
formatInfo.isSupported = true;
- formatInfo.pixelFormat = PIXEL_FORMAT_RGB_565;
+ formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM;
formatInfo.format = GL_RGB;
formatInfo.type = GL_UNSIGNED_SHORT_5_6_5;
formatInfo.vkFormat = VK_FORMAT_R5G6B5_UNORM_PACK16;
break;
case kGray_8_SkColorType:
formatInfo.isSupported = usingGL;
- formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_8888;
+ formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
formatInfo.format = GL_LUMINANCE;
formatInfo.type = GL_UNSIGNED_BYTE;
formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
@@ -394,28 +401,27 @@ sk_sp<Bitmap> HardwareBitmapUploader::allocateHardwareBitmap(const SkBitmap& sou
}
SkBitmap bitmap = makeHwCompatible(format, sourceBitmap);
- sp<GraphicBuffer> buffer = new GraphicBuffer(
- static_cast<uint32_t>(bitmap.width()), static_cast<uint32_t>(bitmap.height()),
- format.pixelFormat,
- GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_NEVER |
- GraphicBuffer::USAGE_SW_READ_NEVER,
- std::string("Bitmap::allocateHardwareBitmap pid [") + std::to_string(getpid()) +
- "]");
-
- status_t error = buffer->initCheck();
- if (error < 0) {
- ALOGW("createGraphicBuffer() failed in GraphicBuffer.create()");
+ AHardwareBuffer_Desc desc = {
+ .width = static_cast<uint32_t>(bitmap.width()),
+ .height = static_cast<uint32_t>(bitmap.height()),
+ .layers = 1,
+ .format = format.bufferFormat,
+ .usage = AHARDWAREBUFFER_USAGE_CPU_READ_NEVER | AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER |
+ AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE,
+ };
+ UniqueAHardwareBuffer ahb = allocateAHardwareBuffer(desc);
+ if (!ahb) {
+ ALOGW("allocateHardwareBitmap() failed in AHardwareBuffer_allocate()");
return nullptr;
- }
+ };
createUploader(usingGL);
- if (!sUploader->uploadHardwareBitmap(bitmap, format, buffer)) {
+ if (!sUploader->uploadHardwareBitmap(bitmap, format, ahb.get())) {
return nullptr;
}
- return Bitmap::createFrom(buffer->toAHardwareBuffer(), bitmap.colorType(),
- bitmap.refColorSpace(), bitmap.alphaType(),
- Bitmap::computePalette(bitmap));
+ return Bitmap::createFrom(ahb.get(), bitmap.colorType(), bitmap.refColorSpace(),
+ bitmap.alphaType(), Bitmap::computePalette(bitmap));
}
void HardwareBitmapUploader::initialize() {
diff --git a/libs/hwui/HardwareBitmapUploader.h b/libs/hwui/HardwareBitmapUploader.h
index 72243d23dd35..ad7a95a4fa03 100644
--- a/libs/hwui/HardwareBitmapUploader.h
+++ b/libs/hwui/HardwareBitmapUploader.h
@@ -20,7 +20,7 @@
namespace android::uirenderer {
-class ANDROID_API HardwareBitmapUploader {
+class HardwareBitmapUploader {
public:
static void initialize();
static void terminate();
diff --git a/libs/hwui/Interpolator.h b/libs/hwui/Interpolator.h
index 452988fc8711..131cc3935f10 100644
--- a/libs/hwui/Interpolator.h
+++ b/libs/hwui/Interpolator.h
@@ -37,12 +37,12 @@ protected:
Interpolator() {}
};
-class ANDROID_API AccelerateDecelerateInterpolator : public Interpolator {
+class AccelerateDecelerateInterpolator : public Interpolator {
public:
virtual float interpolate(float input) override;
};
-class ANDROID_API AccelerateInterpolator : public Interpolator {
+class AccelerateInterpolator : public Interpolator {
public:
explicit AccelerateInterpolator(float factor) : mFactor(factor), mDoubleFactor(factor * 2) {}
virtual float interpolate(float input) override;
@@ -52,7 +52,7 @@ private:
const float mDoubleFactor;
};
-class ANDROID_API AnticipateInterpolator : public Interpolator {
+class AnticipateInterpolator : public Interpolator {
public:
explicit AnticipateInterpolator(float tension) : mTension(tension) {}
virtual float interpolate(float input) override;
@@ -61,7 +61,7 @@ private:
const float mTension;
};
-class ANDROID_API AnticipateOvershootInterpolator : public Interpolator {
+class AnticipateOvershootInterpolator : public Interpolator {
public:
explicit AnticipateOvershootInterpolator(float tension) : mTension(tension) {}
virtual float interpolate(float input) override;
@@ -70,12 +70,12 @@ private:
const float mTension;
};
-class ANDROID_API BounceInterpolator : public Interpolator {
+class BounceInterpolator : public Interpolator {
public:
virtual float interpolate(float input) override;
};
-class ANDROID_API CycleInterpolator : public Interpolator {
+class CycleInterpolator : public Interpolator {
public:
explicit CycleInterpolator(float cycles) : mCycles(cycles) {}
virtual float interpolate(float input) override;
@@ -84,7 +84,7 @@ private:
const float mCycles;
};
-class ANDROID_API DecelerateInterpolator : public Interpolator {
+class DecelerateInterpolator : public Interpolator {
public:
explicit DecelerateInterpolator(float factor) : mFactor(factor) {}
virtual float interpolate(float input) override;
@@ -93,12 +93,12 @@ private:
const float mFactor;
};
-class ANDROID_API LinearInterpolator : public Interpolator {
+class LinearInterpolator : public Interpolator {
public:
virtual float interpolate(float input) override { return input; }
};
-class ANDROID_API OvershootInterpolator : public Interpolator {
+class OvershootInterpolator : public Interpolator {
public:
explicit OvershootInterpolator(float tension) : mTension(tension) {}
virtual float interpolate(float input) override;
@@ -107,7 +107,7 @@ private:
const float mTension;
};
-class ANDROID_API PathInterpolator : public Interpolator {
+class PathInterpolator : public Interpolator {
public:
explicit PathInterpolator(std::vector<float>&& x, std::vector<float>&& y) : mX(x), mY(y) {}
virtual float interpolate(float input) override;
@@ -117,7 +117,7 @@ private:
std::vector<float> mY;
};
-class ANDROID_API LUTInterpolator : public Interpolator {
+class LUTInterpolator : public Interpolator {
public:
LUTInterpolator(float* values, size_t size);
~LUTInterpolator();
diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h
index 0c515a41689d..4c6e1a0a6eee 100644
--- a/libs/hwui/Matrix.h
+++ b/libs/hwui/Matrix.h
@@ -44,7 +44,7 @@ namespace uirenderer {
// Classes
///////////////////////////////////////////////////////////////////////////////
-class ANDROID_API Matrix4 {
+class Matrix4 {
public:
float data[16];
diff --git a/libs/hwui/PathParser.h b/libs/hwui/PathParser.h
index 878bb7c0f137..859697eb3e9b 100644
--- a/libs/hwui/PathParser.h
+++ b/libs/hwui/PathParser.h
@@ -30,17 +30,17 @@ namespace uirenderer {
class PathParser {
public:
- struct ANDROID_API ParseResult {
+ struct ParseResult {
bool failureOccurred = false;
std::string failureMessage;
};
/**
* Parse the string literal and create a Skia Path. Return true on success.
*/
- ANDROID_API static void parseAsciiStringForSkPath(SkPath* outPath, ParseResult* result,
- const char* pathStr, size_t strLength);
- ANDROID_API static void getPathDataFromAsciiString(PathData* outData, ParseResult* result,
- const char* pathStr, size_t strLength);
+ static void parseAsciiStringForSkPath(SkPath* outPath, ParseResult* result,
+ const char* pathStr, size_t strLength);
+ static void getPathDataFromAsciiString(PathData* outData, ParseResult* result,
+ const char* pathStr, size_t strLength);
static void dump(const PathData& data);
static void validateVerbAndPoints(char verb, size_t points, ParseResult* result);
};
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index 446e81e65bb8..ba44d056dda3 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -78,6 +78,7 @@ bool Properties::isolatedProcess = false;
int Properties::contextPriority = 0;
int Properties::defaultRenderAhead = -1;
+float Properties::defaultSdrWhitePoint = 200.f;
bool Properties::load() {
bool prevDebugLayersUpdates = debugLayersUpdates;
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index d3ecb54d94f6..85a0f4aa7809 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -213,10 +213,10 @@ public:
static int overrideSpotShadowStrength;
static ProfileType getProfileType();
- ANDROID_API static RenderPipelineType peekRenderPipelineType();
- ANDROID_API static RenderPipelineType getRenderPipelineType();
+ static RenderPipelineType peekRenderPipelineType();
+ static RenderPipelineType getRenderPipelineType();
- ANDROID_API static bool enableHighContrastText;
+ static bool enableHighContrastText;
// Should be used only by test apps
static bool waitForGpuCompletion;
@@ -235,20 +235,22 @@ public:
static bool skpCaptureEnabled;
// For experimentation b/68769804
- ANDROID_API static bool enableRTAnimations;
+ static bool enableRTAnimations;
// Used for testing only to change the render pipeline.
static void overrideRenderPipelineType(RenderPipelineType);
static bool runningInEmulator;
- ANDROID_API static bool debuggingEnabled;
- ANDROID_API static bool isolatedProcess;
+ static bool debuggingEnabled;
+ static bool isolatedProcess;
- ANDROID_API static int contextPriority;
+ static int contextPriority;
static int defaultRenderAhead;
+ static float defaultSdrWhitePoint;
+
private:
static ProfileType sProfileType;
static bool sDisableProfileBars;
diff --git a/libs/hwui/PropertyValuesAnimatorSet.h b/libs/hwui/PropertyValuesAnimatorSet.h
index e4214b22d1cc..c04a0b9b0fe7 100644
--- a/libs/hwui/PropertyValuesAnimatorSet.h
+++ b/libs/hwui/PropertyValuesAnimatorSet.h
@@ -44,7 +44,7 @@ private:
};
// TODO: This class should really be named VectorDrawableAnimator
-class ANDROID_API PropertyValuesAnimatorSet : public BaseRenderNodeAnimator {
+class PropertyValuesAnimatorSet : public BaseRenderNodeAnimator {
public:
friend class PropertyAnimatorSetListener;
PropertyValuesAnimatorSet();
diff --git a/libs/hwui/PropertyValuesHolder.h b/libs/hwui/PropertyValuesHolder.h
index 0a799d3c0b5c..bb26cbe7bc9b 100644
--- a/libs/hwui/PropertyValuesHolder.h
+++ b/libs/hwui/PropertyValuesHolder.h
@@ -28,7 +28,7 @@ namespace uirenderer {
* When a fraction in [0f, 1f] is provided, the holder will calculate an interpolated value based
* on its start and end value, and set the new value on the VectorDrawble's corresponding property.
*/
-class ANDROID_API PropertyValuesHolder {
+class PropertyValuesHolder {
public:
virtual void setFraction(float fraction) = 0;
virtual ~PropertyValuesHolder() {}
@@ -49,19 +49,19 @@ public:
}
};
-class ANDROID_API ColorEvaluator : public Evaluator<SkColor> {
+class ColorEvaluator : public Evaluator<SkColor> {
public:
virtual void evaluate(SkColor* outColor, const SkColor& from, const SkColor& to,
float fraction) const override;
};
-class ANDROID_API PathEvaluator : public Evaluator<PathData> {
+class PathEvaluator : public Evaluator<PathData> {
virtual void evaluate(PathData* out, const PathData& from, const PathData& to,
float fraction) const override;
};
template <typename T>
-class ANDROID_API PropertyValuesHolderImpl : public PropertyValuesHolder {
+class PropertyValuesHolderImpl : public PropertyValuesHolder {
public:
PropertyValuesHolderImpl(const T& startValue, const T& endValue)
: mStartValue(startValue), mEndValue(endValue) {}
@@ -85,7 +85,7 @@ protected:
T mEndValue;
};
-class ANDROID_API GroupPropertyValuesHolder : public PropertyValuesHolderImpl<float> {
+class GroupPropertyValuesHolder : public PropertyValuesHolderImpl<float> {
public:
GroupPropertyValuesHolder(VectorDrawable::Group* ptr, int propertyId, float startValue,
float endValue)
@@ -99,7 +99,7 @@ private:
int mPropertyId;
};
-class ANDROID_API FullPathColorPropertyValuesHolder : public PropertyValuesHolderImpl<SkColor> {
+class FullPathColorPropertyValuesHolder : public PropertyValuesHolderImpl<SkColor> {
public:
FullPathColorPropertyValuesHolder(VectorDrawable::FullPath* ptr, int propertyId,
SkColor startValue, SkColor endValue)
@@ -116,7 +116,7 @@ private:
int mPropertyId;
};
-class ANDROID_API FullPathPropertyValuesHolder : public PropertyValuesHolderImpl<float> {
+class FullPathPropertyValuesHolder : public PropertyValuesHolderImpl<float> {
public:
FullPathPropertyValuesHolder(VectorDrawable::FullPath* ptr, int propertyId, float startValue,
float endValue)
@@ -132,7 +132,7 @@ private:
int mPropertyId;
};
-class ANDROID_API PathDataPropertyValuesHolder : public PropertyValuesHolderImpl<PathData> {
+class PathDataPropertyValuesHolder : public PropertyValuesHolderImpl<PathData> {
public:
PathDataPropertyValuesHolder(VectorDrawable::Path* ptr, PathData* startValue,
PathData* endValue)
@@ -146,7 +146,7 @@ private:
PathData mPathData;
};
-class ANDROID_API RootAlphaPropertyValuesHolder : public PropertyValuesHolderImpl<float> {
+class RootAlphaPropertyValuesHolder : public PropertyValuesHolderImpl<float> {
public:
RootAlphaPropertyValuesHolder(VectorDrawable::Tree* tree, float startValue, float endValue)
: PropertyValuesHolderImpl(startValue, endValue), mTree(tree) {
diff --git a/libs/hwui/Readback.cpp b/libs/hwui/Readback.cpp
index 39900e65cb8a..b71bb07dbc86 100644
--- a/libs/hwui/Readback.cpp
+++ b/libs/hwui/Readback.cpp
@@ -18,7 +18,6 @@
#include <sync/sync.h>
#include <system/window.h>
-#include <ui/GraphicBuffer.h>
#include "DeferredLayerUpdater.h"
#include "Properties.h"
@@ -28,6 +27,7 @@
#include "renderthread/VulkanManager.h"
#include "utils/Color.h"
#include "utils/MathUtils.h"
+#include "utils/NdkUtils.h"
#include "utils/TraceUtils.h"
using namespace android::uirenderer::renderthread;
@@ -54,8 +54,7 @@ CopyResult Readback::copySurfaceInto(ANativeWindow* window, const Rect& srcRect,
return CopyResult::SourceEmpty;
}
- std::unique_ptr<AHardwareBuffer, decltype(&AHardwareBuffer_release)> sourceBuffer(
- rawSourceBuffer, AHardwareBuffer_release);
+ UniqueAHardwareBuffer sourceBuffer{rawSourceBuffer};
AHardwareBuffer_Desc description;
AHardwareBuffer_describe(sourceBuffer.get(), &description);
if (description.usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT) {
@@ -119,7 +118,7 @@ CopyResult Readback::copyImageInto(const sk_sp<SkImage>& image, Matrix4& texTran
}
int imgWidth = image->width();
int imgHeight = image->height();
- sk_sp<GrContext> grContext = sk_ref_sp(mRenderThread.getGrContext());
+ sk_sp<GrDirectContext> grContext = sk_ref_sp(mRenderThread.getGrContext());
if (bitmap->colorType() == kRGBA_F16_SkColorType &&
!grContext->colorTypeSupportedAsSurface(bitmap->colorType())) {
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index dc467c41baed..892d43a763a9 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -96,7 +96,7 @@ struct Restore final : Op {
struct SaveLayer final : Op {
static const auto kType = Type::SaveLayer;
SaveLayer(const SkRect* bounds, const SkPaint* paint, const SkImageFilter* backdrop,
- const SkImage* clipMask, const SkMatrix* clipMatrix, SkCanvas::SaveLayerFlags flags) {
+ SkCanvas::SaveLayerFlags flags) {
if (bounds) {
this->bounds = *bounds;
}
@@ -104,19 +104,14 @@ struct SaveLayer final : Op {
this->paint = *paint;
}
this->backdrop = sk_ref_sp(backdrop);
- this->clipMask = sk_ref_sp(clipMask);
- this->clipMatrix = clipMatrix ? *clipMatrix : SkMatrix::I();
this->flags = flags;
}
SkRect bounds = kUnset;
SkPaint paint;
sk_sp<const SkImageFilter> backdrop;
- sk_sp<const SkImage> clipMask;
- SkMatrix clipMatrix;
SkCanvas::SaveLayerFlags flags;
void draw(SkCanvas* c, const SkMatrix&) const {
- c->saveLayer({maybe_unset(bounds), &paint, backdrop.get(), clipMask.get(),
- clipMatrix.isIdentity() ? nullptr : &clipMatrix, flags});
+ c->saveLayer({maybe_unset(bounds), &paint, backdrop.get(), flags});
}
};
struct SaveBehind final : Op {
@@ -132,9 +127,9 @@ struct SaveBehind final : Op {
struct Concat44 final : Op {
static const auto kType = Type::Concat44;
- Concat44(const SkScalar m[16]) { memcpy(colMajor, m, sizeof(colMajor)); }
- SkScalar colMajor[16];
- void draw(SkCanvas* c, const SkMatrix&) const { c->experimental_concat44(colMajor); }
+ Concat44(const SkM44& m) : matrix(m) {}
+ SkM44 matrix;
+ void draw(SkCanvas* c, const SkMatrix&) const { c->concat(matrix); }
};
struct Concat final : Op {
static const auto kType = Type::Concat;
@@ -448,14 +443,13 @@ struct DrawPoints final : Op {
};
struct DrawVertices final : Op {
static const auto kType = Type::DrawVertices;
- DrawVertices(const SkVertices* v, int bc, SkBlendMode m, const SkPaint& p)
- : vertices(sk_ref_sp(const_cast<SkVertices*>(v))), boneCount(bc), mode(m), paint(p) {}
+ DrawVertices(const SkVertices* v, SkBlendMode m, const SkPaint& p)
+ : vertices(sk_ref_sp(const_cast<SkVertices*>(v))), mode(m), paint(p) {}
sk_sp<SkVertices> vertices;
- int boneCount;
SkBlendMode mode;
SkPaint paint;
void draw(SkCanvas* c, const SkMatrix&) const {
- c->drawVertices(vertices, pod<SkVertices::Bone>(this), boneCount, mode, paint);
+ c->drawVertices(vertices, mode, paint);
}
};
struct DrawAtlas final : Op {
@@ -565,17 +559,16 @@ void DisplayListData::restore() {
this->push<Restore>(0);
}
void DisplayListData::saveLayer(const SkRect* bounds, const SkPaint* paint,
- const SkImageFilter* backdrop, const SkImage* clipMask,
- const SkMatrix* clipMatrix, SkCanvas::SaveLayerFlags flags) {
- this->push<SaveLayer>(0, bounds, paint, backdrop, clipMask, clipMatrix, flags);
+ const SkImageFilter* backdrop, SkCanvas::SaveLayerFlags flags) {
+ this->push<SaveLayer>(0, bounds, paint, backdrop, flags);
}
void DisplayListData::saveBehind(const SkRect* subset) {
this->push<SaveBehind>(0, subset);
}
-void DisplayListData::concat44(const SkScalar colMajor[16]) {
- this->push<Concat44>(0, colMajor);
+void DisplayListData::concat(const SkM44& m) {
+ this->push<Concat44>(0, m);
}
void DisplayListData::concat(const SkMatrix& matrix) {
this->push<Concat>(0, matrix);
@@ -686,11 +679,8 @@ void DisplayListData::drawPoints(SkCanvas::PointMode mode, size_t count, const S
void* pod = this->push<DrawPoints>(count * sizeof(SkPoint), mode, count, paint);
copy_v(pod, points, count);
}
-void DisplayListData::drawVertices(const SkVertices* vertices, const SkVertices::Bone bones[],
- int boneCount, SkBlendMode mode, const SkPaint& paint) {
- void* pod = this->push<DrawVertices>(boneCount * sizeof(SkVertices::Bone), vertices, boneCount,
- mode, paint);
- copy_v(pod, bones, boneCount);
+void DisplayListData::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
+ this->push<DrawVertices>(0, vertices, mode, paint);
}
void DisplayListData::drawAtlas(const SkImage* atlas, const SkRSXform xforms[], const SkRect texs[],
const SkColor colors[], int count, SkBlendMode xfermode,
@@ -823,8 +813,7 @@ void RecordingCanvas::willSave() {
fDL->save();
}
SkCanvas::SaveLayerStrategy RecordingCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
- fDL->saveLayer(rec.fBounds, rec.fPaint, rec.fBackdrop, rec.fClipMask, rec.fClipMatrix,
- rec.fSaveLayerFlags);
+ fDL->saveLayer(rec.fBounds, rec.fPaint, rec.fBackdrop, rec.fSaveLayerFlags);
return SkCanvas::kNoLayer_SaveLayerStrategy;
}
void RecordingCanvas::willRestore() {
@@ -841,8 +830,8 @@ bool RecordingCanvas::onDoSaveBehind(const SkRect* subset) {
return false;
}
-void RecordingCanvas::didConcat44(const SkScalar colMajor[16]) {
- fDL->concat44(colMajor);
+void RecordingCanvas::didConcat44(const SkM44& m) {
+ fDL->concat(m);
}
void RecordingCanvas::didConcat(const SkMatrix& matrix) {
fDL->concat(matrix);
@@ -929,24 +918,6 @@ void RecordingCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScala
fDL->drawTextBlob(blob, x, y, paint);
}
-void RecordingCanvas::onDrawBitmap(const SkBitmap& bm, SkScalar x, SkScalar y,
- const SkPaint* paint) {
- fDL->drawImage(SkImage::MakeFromBitmap(bm), x, y, paint, BitmapPalette::Unknown);
-}
-void RecordingCanvas::onDrawBitmapNine(const SkBitmap& bm, const SkIRect& center, const SkRect& dst,
- const SkPaint* paint) {
- fDL->drawImageNine(SkImage::MakeFromBitmap(bm), center, dst, paint);
-}
-void RecordingCanvas::onDrawBitmapRect(const SkBitmap& bm, const SkRect* src, const SkRect& dst,
- const SkPaint* paint, SrcRectConstraint constraint) {
- fDL->drawImageRect(SkImage::MakeFromBitmap(bm), src, dst, paint, constraint,
- BitmapPalette::Unknown);
-}
-void RecordingCanvas::onDrawBitmapLattice(const SkBitmap& bm, const SkCanvas::Lattice& lattice,
- const SkRect& dst, const SkPaint* paint) {
- fDL->drawImageLattice(SkImage::MakeFromBitmap(bm), lattice, dst, paint, BitmapPalette::Unknown);
-}
-
void RecordingCanvas::drawImage(const sk_sp<SkImage>& image, SkScalar x, SkScalar y,
const SkPaint* paint, BitmapPalette palette) {
fDL->drawImage(image, x, y, paint, palette);
@@ -1007,9 +978,8 @@ void RecordingCanvas::onDrawPoints(SkCanvas::PointMode mode, size_t count, const
fDL->drawPoints(mode, count, pts, paint);
}
void RecordingCanvas::onDrawVerticesObject(const SkVertices* vertices,
- const SkVertices::Bone bones[], int boneCount,
SkBlendMode mode, const SkPaint& paint) {
- fDL->drawVertices(vertices, bones, boneCount, mode, paint);
+ fDL->drawVertices(vertices, mode, paint);
}
void RecordingCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xforms[],
const SkRect texs[], const SkColor colors[], int count,
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index 7eb1ce3eb18a..63d120c4ca19 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -77,12 +77,11 @@ private:
void flush();
void save();
- void saveLayer(const SkRect*, const SkPaint*, const SkImageFilter*, const SkImage*,
- const SkMatrix*, SkCanvas::SaveLayerFlags);
+ void saveLayer(const SkRect*, const SkPaint*, const SkImageFilter*, SkCanvas::SaveLayerFlags);
void saveBehind(const SkRect*);
void restore();
- void concat44(const SkScalar colMajor[16]);
+ void concat(const SkM44&);
void concat(const SkMatrix&);
void setMatrix(const SkMatrix&);
void scale(SkScalar, SkScalar);
@@ -120,8 +119,7 @@ private:
void drawPatch(const SkPoint[12], const SkColor[4], const SkPoint[4], SkBlendMode,
const SkPaint&);
void drawPoints(SkCanvas::PointMode, size_t, const SkPoint[], const SkPaint&);
- void drawVertices(const SkVertices*, const SkVertices::Bone bones[], int boneCount, SkBlendMode,
- const SkPaint&);
+ void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&);
void drawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], int,
SkBlendMode, const SkRect*, const SkPaint*);
void drawShadowRec(const SkPath&, const SkDrawShadowRec&);
@@ -155,7 +153,7 @@ public:
void onFlush() override;
- void didConcat44(const SkScalar[16]) override;
+ void didConcat44(const SkM44&) override;
void didConcat(const SkMatrix&) override;
void didSetMatrix(const SkMatrix&) override;
void didScale(SkScalar, SkScalar) override;
@@ -182,13 +180,6 @@ public:
void onDrawTextBlob(const SkTextBlob*, SkScalar, SkScalar, const SkPaint&) override;
- void onDrawBitmap(const SkBitmap&, SkScalar, SkScalar, const SkPaint*) override;
- void onDrawBitmapLattice(const SkBitmap&, const Lattice&, const SkRect&,
- const SkPaint*) override;
- void onDrawBitmapNine(const SkBitmap&, const SkIRect&, const SkRect&, const SkPaint*) override;
- void onDrawBitmapRect(const SkBitmap&, const SkRect*, const SkRect&, const SkPaint*,
- SrcRectConstraint) override;
-
void drawImage(const sk_sp<SkImage>& image, SkScalar left, SkScalar top, const SkPaint* paint,
BitmapPalette pallete);
@@ -206,8 +197,7 @@ public:
void onDrawPatch(const SkPoint[12], const SkColor[4], const SkPoint[4], SkBlendMode,
const SkPaint&) override;
void onDrawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) override;
- void onDrawVerticesObject(const SkVertices*, const SkVertices::Bone bones[], int boneCount,
- SkBlendMode, const SkPaint&) override;
+ void onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint&) override;
void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], int,
SkBlendMode, const SkRect*, const SkPaint*) override;
void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&) override;
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index c0ec2174bb35..6d5e62e955bb 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -94,17 +94,17 @@ public:
DISPLAY_LIST = 1 << 14,
};
- ANDROID_API RenderNode();
- ANDROID_API virtual ~RenderNode();
+ RenderNode();
+ virtual ~RenderNode();
// See flags defined in DisplayList.java
enum ReplayFlag { kReplayFlag_ClipChildren = 0x1 };
- ANDROID_API void setStagingDisplayList(DisplayList* newData);
+ void setStagingDisplayList(DisplayList* newData);
- ANDROID_API void output();
- ANDROID_API int getUsageSize();
- ANDROID_API int getAllocatedSize();
+ void output();
+ int getUsageSize();
+ int getAllocatedSize();
bool isRenderable() const { return mDisplayList && !mDisplayList->isEmpty(); }
@@ -149,12 +149,12 @@ public:
int getHeight() const { return properties().getHeight(); }
- ANDROID_API virtual void prepareTree(TreeInfo& info);
+ virtual void prepareTree(TreeInfo& info);
void destroyHardwareResources(TreeInfo* info = nullptr);
void destroyLayers();
// UI thread only!
- ANDROID_API void addAnimator(const sp<BaseRenderNodeAnimator>& animator);
+ void addAnimator(const sp<BaseRenderNodeAnimator>& animator);
void removeAnimator(const sp<BaseRenderNodeAnimator>& animator);
// This can only happen during pushStaging()
@@ -179,7 +179,7 @@ public:
// the frameNumber to appropriately batch/synchronize these transactions.
// There is no other filtering/batching to ensure that only the "final"
// state called once per frame.
- class ANDROID_API PositionListener : public VirtualLightRefBase {
+ class PositionListener : public VirtualLightRefBase {
public:
virtual ~PositionListener() {}
// Called when the RenderNode's position changes
@@ -190,14 +190,14 @@ public:
virtual void onPositionLost(RenderNode& node, const TreeInfo* info) = 0;
};
- ANDROID_API void setPositionListener(PositionListener* listener) {
+ void setPositionListener(PositionListener* listener) {
mStagingPositionListener = listener;
mPositionListenerDirty = true;
}
// This is only modified in MODE_FULL, so it can be safely accessed
// on the UI thread.
- ANDROID_API bool hasParents() { return mParentCount; }
+ bool hasParents() { return mParentCount; }
void onRemovedFromTree(TreeInfo* info);
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index 24f6035b6708..ef4cd1f1eb62 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -69,7 +69,7 @@ enum ClippingFlags {
CLIP_TO_CLIP_BOUNDS = 0x1 << 1,
};
-class ANDROID_API LayerProperties {
+class LayerProperties {
public:
bool setType(LayerType type) {
if (RP_SET(mType, type)) {
@@ -123,7 +123,7 @@ private:
/*
* Data structure that holds the properties for a RenderNode
*/
-class ANDROID_API RenderProperties {
+class RenderProperties {
public:
RenderProperties();
virtual ~RenderProperties();
diff --git a/libs/hwui/RootRenderNode.h b/libs/hwui/RootRenderNode.h
index 12de4ecac94b..1d3f5a8a51e0 100644
--- a/libs/hwui/RootRenderNode.h
+++ b/libs/hwui/RootRenderNode.h
@@ -27,16 +27,16 @@
namespace android::uirenderer {
-class ANDROID_API RootRenderNode : public RenderNode {
+class RootRenderNode : public RenderNode {
public:
- ANDROID_API explicit RootRenderNode(std::unique_ptr<ErrorHandler> errorHandler)
+ explicit RootRenderNode(std::unique_ptr<ErrorHandler> errorHandler)
: RenderNode(), mErrorHandler(std::move(errorHandler)) {}
- ANDROID_API virtual ~RootRenderNode() {}
+ virtual ~RootRenderNode() {}
virtual void prepareTree(TreeInfo& info) override;
- ANDROID_API void attachAnimatingNode(RenderNode* animatingNode);
+ void attachAnimatingNode(RenderNode* animatingNode);
void attachPendingVectorDrawableAnimators();
@@ -53,9 +53,9 @@ public:
void pushStagingVectorDrawableAnimators(AnimationContext* context);
- ANDROID_API void destroy();
+ void destroy();
- ANDROID_API void addVectorDrawableAnimator(PropertyValuesAnimatorSet* anim);
+ void addVectorDrawableAnimator(PropertyValuesAnimatorSet* anim);
private:
const std::unique_ptr<ErrorHandler> mErrorHandler;
@@ -75,12 +75,11 @@ private:
};
#ifdef __ANDROID__ // Layoutlib does not support Animations
-class ANDROID_API ContextFactoryImpl : public IContextFactory {
+class ContextFactoryImpl : public IContextFactory {
public:
- ANDROID_API explicit ContextFactoryImpl(RootRenderNode* rootNode) : mRootNode(rootNode) {}
+ explicit ContextFactoryImpl(RootRenderNode* rootNode) : mRootNode(rootNode) {}
- ANDROID_API virtual AnimationContext* createAnimationContext(
- renderthread::TimeLord& clock) override;
+ virtual AnimationContext* createAnimationContext(renderthread::TimeLord& clock) override;
private:
RootRenderNode* mRootNode;
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 941437998838..242b8b0d139e 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -40,6 +40,7 @@
#include <SkShader.h>
#include <SkTemplates.h>
#include <SkTextBlob.h>
+#include <SkVertices.h>
#include <memory>
#include <optional>
@@ -842,9 +843,4 @@ void SkiaCanvas::drawRenderNode(uirenderer::RenderNode* renderNode) {
LOG_ALWAYS_FATAL("SkiaCanvas can't directly draw RenderNodes");
}
-void SkiaCanvas::callDrawGLFunction(Functor* functor,
- uirenderer::GlFunctorLifecycleListener* listener) {
- LOG_ALWAYS_FATAL("SkiaCanvas can't directly draw GL Content");
-}
-
} // namespace android
diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h
index 1eb089d8764c..1df2b2671659 100644
--- a/libs/hwui/SkiaCanvas.h
+++ b/libs/hwui/SkiaCanvas.h
@@ -57,8 +57,8 @@ public:
LOG_ALWAYS_FATAL("SkiaCanvas does not produce a DisplayList");
return nullptr;
}
- virtual void insertReorderBarrier(bool enableReorder) override {
- LOG_ALWAYS_FATAL("SkiaCanvas does not support reordering barriers");
+ virtual void enableZ(bool enableZ) override {
+ LOG_ALWAYS_FATAL("SkiaCanvas does not support enableZ");
}
virtual void setBitmap(const SkBitmap& bitmap) override;
@@ -152,8 +152,6 @@ public:
virtual void drawLayer(uirenderer::DeferredLayerUpdater* layerHandle) override;
virtual void drawRenderNode(uirenderer::RenderNode* renderNode) override;
- virtual void callDrawGLFunction(Functor* functor,
- uirenderer::GlFunctorLifecycleListener* listener) override;
virtual void drawPicture(const SkPicture& picture) override;
protected:
diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h
index e1b6f2adde74..ac7d41e0d600 100644
--- a/libs/hwui/VectorDrawable.h
+++ b/libs/hwui/VectorDrawable.h
@@ -97,7 +97,7 @@ private:
bool* mStagingDirty;
};
-class ANDROID_API Node {
+class Node {
public:
class Properties {
public:
@@ -127,9 +127,9 @@ protected:
PropertyChangedListener* mPropertyChangedListener = nullptr;
};
-class ANDROID_API Path : public Node {
+class Path : public Node {
public:
- struct ANDROID_API Data {
+ struct Data {
std::vector<char> verbs;
std::vector<size_t> verbSizes;
std::vector<float> points;
@@ -200,7 +200,7 @@ private:
bool mStagingPropertiesDirty = true;
};
-class ANDROID_API FullPath : public Path {
+class FullPath : public Path {
public:
class FullPathProperties : public Properties {
public:
@@ -369,7 +369,7 @@ private:
bool mAntiAlias = true;
};
-class ANDROID_API ClipPath : public Path {
+class ClipPath : public Path {
public:
ClipPath(const ClipPath& path) : Path(path) {}
ClipPath(const char* path, size_t strLength) : Path(path, strLength) {}
@@ -378,7 +378,7 @@ public:
virtual void setAntiAlias(bool aa) {}
};
-class ANDROID_API Group : public Node {
+class Group : public Node {
public:
class GroupProperties : public Properties {
public:
@@ -498,7 +498,7 @@ private:
std::vector<std::unique_ptr<Node> > mChildren;
};
-class ANDROID_API Tree : public VirtualLightRefBase {
+class Tree : public VirtualLightRefBase {
public:
explicit Tree(Group* rootNode) : mRootNode(rootNode) {
mRootNode->setPropertyChangedListener(&mPropertyChangedListener);
diff --git a/libs/hwui/apex/java/android/graphics/ColorMatrix.java b/libs/hwui/apex/java/android/graphics/ColorMatrix.java
new file mode 100644
index 000000000000..6299b2c47ea1
--- /dev/null
+++ b/libs/hwui/apex/java/android/graphics/ColorMatrix.java
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 java.util.Arrays;
+
+/**
+ * 4x5 matrix for transforming the color and alpha components of a Bitmap.
+ * The matrix can be passed as single array, and is treated as follows:
+ *
+ * <pre>
+ * [ a, b, c, d, e,
+ * f, g, h, i, j,
+ * k, l, m, n, o,
+ * p, q, r, s, t ]</pre>
+ *
+ * <p>
+ * When applied to a color <code>[R, G, B, A]</code>, the resulting color
+ * is computed as:
+ * </p>
+ *
+ * <pre>
+ * R&rsquo; = a*R + b*G + c*B + d*A + e;
+ * G&rsquo; = f*R + g*G + h*B + i*A + j;
+ * B&rsquo; = k*R + l*G + m*B + n*A + o;
+ * A&rsquo; = p*R + q*G + r*B + s*A + t;</pre>
+ *
+ * <p>
+ * That resulting color <code>[R&rsquo;, G&rsquo;, B&rsquo;, A&rsquo;]</code>
+ * then has each channel clamped to the <code>0</code> to <code>255</code>
+ * range.
+ * </p>
+ *
+ * <p>
+ * The sample ColorMatrix below inverts incoming colors by scaling each
+ * channel by <code>-1</code>, and then shifting the result up by
+ * <code>255</code> to remain in the standard color space.
+ * </p>
+ *
+ * <pre>
+ * [ -1, 0, 0, 0, 255,
+ * 0, -1, 0, 0, 255,
+ * 0, 0, -1, 0, 255,
+ * 0, 0, 0, 1, 0 ]</pre>
+ */
+@SuppressWarnings({ "MismatchedReadAndWriteOfArray", "PointlessArithmeticExpression" })
+public class ColorMatrix {
+ private final float[] mArray = new float[20];
+
+ /**
+ * Create a new colormatrix initialized to identity (as if reset() had
+ * been called).
+ */
+ public ColorMatrix() {
+ reset();
+ }
+
+ /**
+ * Create a new colormatrix initialized with the specified array of values.
+ */
+ public ColorMatrix(float[] src) {
+ System.arraycopy(src, 0, mArray, 0, 20);
+ }
+
+ /**
+ * Create a new colormatrix initialized with the specified colormatrix.
+ */
+ public ColorMatrix(ColorMatrix src) {
+ System.arraycopy(src.mArray, 0, mArray, 0, 20);
+ }
+
+ /**
+ * Return the array of floats representing this colormatrix.
+ */
+ public final float[] getArray() { return mArray; }
+
+ /**
+ * Set this colormatrix to identity:
+ * <pre>
+ * [ 1 0 0 0 0 - red vector
+ * 0 1 0 0 0 - green vector
+ * 0 0 1 0 0 - blue vector
+ * 0 0 0 1 0 ] - alpha vector
+ * </pre>
+ */
+ public void reset() {
+ final float[] a = mArray;
+ Arrays.fill(a, 0);
+ a[0] = a[6] = a[12] = a[18] = 1;
+ }
+
+ /**
+ * Assign the src colormatrix into this matrix, copying all of its values.
+ */
+ public void set(ColorMatrix src) {
+ System.arraycopy(src.mArray, 0, mArray, 0, 20);
+ }
+
+ /**
+ * Assign the array of floats into this matrix, copying all of its values.
+ */
+ public void set(float[] src) {
+ System.arraycopy(src, 0, mArray, 0, 20);
+ }
+
+ /**
+ * Set this colormatrix to scale by the specified values.
+ */
+ public void setScale(float rScale, float gScale, float bScale,
+ float aScale) {
+ final float[] a = mArray;
+
+ for (int i = 19; i > 0; --i) {
+ a[i] = 0;
+ }
+ a[0] = rScale;
+ a[6] = gScale;
+ a[12] = bScale;
+ a[18] = aScale;
+ }
+
+ /**
+ * Set the rotation on a color axis by the specified values.
+ * <p>
+ * <code>axis=0</code> correspond to a rotation around the RED color
+ * <code>axis=1</code> correspond to a rotation around the GREEN color
+ * <code>axis=2</code> correspond to a rotation around the BLUE color
+ * </p>
+ */
+ public void setRotate(int axis, float degrees) {
+ reset();
+ double radians = degrees * Math.PI / 180d;
+ float cosine = (float) Math.cos(radians);
+ float sine = (float) Math.sin(radians);
+ switch (axis) {
+ // Rotation around the red color
+ case 0:
+ mArray[6] = mArray[12] = cosine;
+ mArray[7] = sine;
+ mArray[11] = -sine;
+ break;
+ // Rotation around the green color
+ case 1:
+ mArray[0] = mArray[12] = cosine;
+ mArray[2] = -sine;
+ mArray[10] = sine;
+ break;
+ // Rotation around the blue color
+ case 2:
+ mArray[0] = mArray[6] = cosine;
+ mArray[1] = sine;
+ mArray[5] = -sine;
+ break;
+ default:
+ throw new RuntimeException();
+ }
+ }
+
+ /**
+ * Set this colormatrix to the concatenation of the two specified
+ * colormatrices, such that the resulting colormatrix has the same effect
+ * as applying matB and then applying matA.
+ * <p>
+ * It is legal for either matA or matB to be the same colormatrix as this.
+ * </p>
+ */
+ public void setConcat(ColorMatrix matA, ColorMatrix matB) {
+ float[] tmp;
+ if (matA == this || matB == this) {
+ tmp = new float[20];
+ } else {
+ tmp = mArray;
+ }
+
+ final float[] a = matA.mArray;
+ final float[] b = matB.mArray;
+ int index = 0;
+ for (int j = 0; j < 20; j += 5) {
+ for (int i = 0; i < 4; i++) {
+ tmp[index++] = a[j + 0] * b[i + 0] + a[j + 1] * b[i + 5] +
+ a[j + 2] * b[i + 10] + a[j + 3] * b[i + 15];
+ }
+ tmp[index++] = a[j + 0] * b[4] + a[j + 1] * b[9] +
+ a[j + 2] * b[14] + a[j + 3] * b[19] +
+ a[j + 4];
+ }
+
+ if (tmp != mArray) {
+ System.arraycopy(tmp, 0, mArray, 0, 20);
+ }
+ }
+
+ /**
+ * Concat this colormatrix with the specified prematrix.
+ * <p>
+ * This is logically the same as calling setConcat(this, prematrix);
+ * </p>
+ */
+ public void preConcat(ColorMatrix prematrix) {
+ setConcat(this, prematrix);
+ }
+
+ /**
+ * Concat this colormatrix with the specified postmatrix.
+ * <p>
+ * This is logically the same as calling setConcat(postmatrix, this);
+ * </p>
+ */
+ public void postConcat(ColorMatrix postmatrix) {
+ setConcat(postmatrix, this);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Set the matrix to affect the saturation of colors.
+ *
+ * @param sat A value of 0 maps the color to gray-scale. 1 is identity.
+ */
+ public void setSaturation(float sat) {
+ reset();
+ float[] m = mArray;
+
+ final float invSat = 1 - sat;
+ final float R = 0.213f * invSat;
+ final float G = 0.715f * invSat;
+ final float B = 0.072f * invSat;
+
+ m[0] = R + sat; m[1] = G; m[2] = B;
+ m[5] = R; m[6] = G + sat; m[7] = B;
+ m[10] = R; m[11] = G; m[12] = B + sat;
+ }
+
+ /**
+ * Set the matrix to convert RGB to YUV
+ */
+ public void setRGB2YUV() {
+ reset();
+ float[] m = mArray;
+ // these coefficients match those in libjpeg
+ m[0] = 0.299f; m[1] = 0.587f; m[2] = 0.114f;
+ m[5] = -0.16874f; m[6] = -0.33126f; m[7] = 0.5f;
+ m[10] = 0.5f; m[11] = -0.41869f; m[12] = -0.08131f;
+ }
+
+ /**
+ * Set the matrix to convert from YUV to RGB
+ */
+ public void setYUV2RGB() {
+ reset();
+ float[] m = mArray;
+ // these coefficients match those in libjpeg
+ m[2] = 1.402f;
+ m[5] = 1; m[6] = -0.34414f; m[7] = -0.71414f;
+ m[10] = 1; m[11] = 1.772f; m[12] = 0;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ // if (obj == this) return true; -- NaN value would mean matrix != itself
+ if (!(obj instanceof ColorMatrix)) {
+ return false;
+ }
+
+ // we don't use Arrays.equals(), since that considers NaN == NaN
+ final float[] other = ((ColorMatrix) obj).mArray;
+ for (int i = 0; i < 20; i++) {
+ if (other[i] != mArray[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
diff --git a/libs/hwui/apex/jni_runtime.cpp b/libs/hwui/apex/jni_runtime.cpp
index a114e2f42157..12e2e8135278 100644
--- a/libs/hwui/apex/jni_runtime.cpp
+++ b/libs/hwui/apex/jni_runtime.cpp
@@ -16,14 +16,14 @@
#include "android/graphics/jni_runtime.h"
-#include <android/log.h>
-#include <nativehelper/JNIHelp.h>
-#include <sys/cdefs.h>
-
#include <EGL/egl.h>
#include <GraphicsJNI.h>
#include <Properties.h>
#include <SkGraphics.h>
+#include <android/log.h>
+#include <nativehelper/JNIHelp.h>
+#include <sys/cdefs.h>
+#include <vulkan/vulkan.h>
#undef LOG_TAG
#define LOG_TAG "AndroidGraphicsJNI"
@@ -61,6 +61,7 @@ extern int register_android_graphics_Path(JNIEnv* env);
extern int register_android_graphics_PathMeasure(JNIEnv* env);
extern int register_android_graphics_Picture(JNIEnv*);
extern int register_android_graphics_Region(JNIEnv* env);
+extern int register_android_graphics_TextureLayer(JNIEnv* env);
extern int register_android_graphics_animation_NativeInterpolatorFactory(JNIEnv* env);
extern int register_android_graphics_animation_RenderNodeAnimator(JNIEnv* env);
extern int register_android_graphics_drawable_AnimatedVectorDrawable(JNIEnv* env);
@@ -76,7 +77,6 @@ extern int register_android_graphics_text_LineBreaker(JNIEnv *env);
extern int register_android_util_PathParser(JNIEnv* env);
extern int register_android_view_DisplayListCanvas(JNIEnv* env);
extern int register_android_view_RenderNode(JNIEnv* env);
-extern int register_android_view_TextureLayer(JNIEnv* env);
extern int register_android_view_ThreadedRenderer(JNIEnv* env);
#ifdef NDEBUG
@@ -123,6 +123,7 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_graphics_Picture),
REG_JNI(register_android_graphics_Region),
REG_JNI(register_android_graphics_Shader),
+ REG_JNI(register_android_graphics_TextureLayer),
REG_JNI(register_android_graphics_Typeface),
REG_JNI(register_android_graphics_YuvImage),
REG_JNI(register_android_graphics_animation_NativeInterpolatorFactory),
@@ -140,7 +141,6 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_util_PathParser),
REG_JNI(register_android_view_RenderNode),
REG_JNI(register_android_view_DisplayListCanvas),
- REG_JNI(register_android_view_TextureLayer),
REG_JNI(register_android_view_ThreadedRenderer),
};
@@ -172,6 +172,11 @@ using android::uirenderer::RenderPipelineType;
void zygote_preload_graphics() {
if (Properties::peekRenderPipelineType() == RenderPipelineType::SkiaGL) {
+ // Preload GL driver if HWUI renders with GL backend.
eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ } else {
+ // Preload Vulkan driver if HWUI renders with Vulkan backend.
+ uint32_t apiVersion;
+ vkEnumerateInstanceVersion(&apiVersion);
}
-} \ No newline at end of file
+}
diff --git a/libs/hwui/api/current.txt b/libs/hwui/api/current.txt
new file mode 100644
index 000000000000..c396a2032eed
--- /dev/null
+++ b/libs/hwui/api/current.txt
@@ -0,0 +1,23 @@
+// Signature format: 2.0
+package android.graphics {
+
+ public class ColorMatrix {
+ ctor public ColorMatrix();
+ ctor public ColorMatrix(float[]);
+ ctor public ColorMatrix(android.graphics.ColorMatrix);
+ method public final float[] getArray();
+ method public void postConcat(android.graphics.ColorMatrix);
+ method public void preConcat(android.graphics.ColorMatrix);
+ method public void reset();
+ method public void set(android.graphics.ColorMatrix);
+ method public void set(float[]);
+ method public void setConcat(android.graphics.ColorMatrix, android.graphics.ColorMatrix);
+ method public void setRGB2YUV();
+ method public void setRotate(int, float);
+ method public void setSaturation(float);
+ method public void setScale(float, float, float, float);
+ method public void setYUV2RGB();
+ }
+
+}
+
diff --git a/libs/hwui/api/module-lib-current.txt b/libs/hwui/api/module-lib-current.txt
new file mode 100644
index 000000000000..d802177e249b
--- /dev/null
+++ b/libs/hwui/api/module-lib-current.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/libs/hwui/api/module-lib-removed.txt b/libs/hwui/api/module-lib-removed.txt
new file mode 100644
index 000000000000..d802177e249b
--- /dev/null
+++ b/libs/hwui/api/module-lib-removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/libs/hwui/api/removed.txt b/libs/hwui/api/removed.txt
new file mode 100644
index 000000000000..d802177e249b
--- /dev/null
+++ b/libs/hwui/api/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/libs/hwui/api/system-current.txt b/libs/hwui/api/system-current.txt
new file mode 100644
index 000000000000..d802177e249b
--- /dev/null
+++ b/libs/hwui/api/system-current.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/libs/hwui/api/system-removed.txt b/libs/hwui/api/system-removed.txt
new file mode 100644
index 000000000000..d802177e249b
--- /dev/null
+++ b/libs/hwui/api/system-removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/libs/hwui/hwui/AnimatedImageDrawable.h b/libs/hwui/hwui/AnimatedImageDrawable.h
index f0aa35acf71b..f81a5a40b44e 100644
--- a/libs/hwui/hwui/AnimatedImageDrawable.h
+++ b/libs/hwui/hwui/AnimatedImageDrawable.h
@@ -44,7 +44,7 @@ public:
* This class can be drawn into Canvas.h and maintains the state needed to drive
* the animation from the RenderThread.
*/
-class ANDROID_API AnimatedImageDrawable : public SkDrawable {
+class AnimatedImageDrawable : public SkDrawable {
public:
// bytesUsed includes the approximate sizes of the SkAnimatedImage and the SkPictures in the
// Snapshots.
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index 60ef4371d38d..1a89cfd5d0ad 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -33,7 +33,6 @@
#ifndef _WIN32
#include <binder/IServiceManager.h>
#endif
-#include <ui/PixelFormat.h>
#include <SkCanvas.h>
#include <SkImagePriv.h>
@@ -132,15 +131,8 @@ sk_sp<Bitmap> Bitmap::allocateHeapBitmap(size_t size, const SkImageInfo& info, s
return sk_sp<Bitmap>(new Bitmap(addr, size, info, rowBytes));
}
-void FreePixelRef(void* addr, void* context) {
- auto pixelRef = (SkPixelRef*)context;
- pixelRef->unref();
-}
-
sk_sp<Bitmap> Bitmap::createFrom(const SkImageInfo& info, SkPixelRef& pixelRef) {
- pixelRef.ref();
- return sk_sp<Bitmap>(new Bitmap((void*)pixelRef.pixels(), (void*)&pixelRef, FreePixelRef, info,
- pixelRef.rowBytes()));
+ return sk_sp<Bitmap>(new Bitmap(pixelRef, info));
}
@@ -230,14 +222,12 @@ Bitmap::Bitmap(void* address, size_t size, const SkImageInfo& info, size_t rowBy
mPixelStorage.heap.size = size;
}
-Bitmap::Bitmap(void* address, void* context, FreeFunc freeFunc, const SkImageInfo& info,
- size_t rowBytes)
- : SkPixelRef(info.width(), info.height(), address, rowBytes)
+Bitmap::Bitmap(SkPixelRef& pixelRef, const SkImageInfo& info)
+ : SkPixelRef(info.width(), info.height(), pixelRef.pixels(), pixelRef.rowBytes())
, mInfo(validateAlpha(info))
- , mPixelStorageType(PixelStorageType::External) {
- mPixelStorage.external.address = address;
- mPixelStorage.external.context = context;
- mPixelStorage.external.freeFunc = freeFunc;
+ , mPixelStorageType(PixelStorageType::WrappedPixelRef) {
+ pixelRef.ref();
+ mPixelStorage.wrapped.pixelRef = &pixelRef;
}
Bitmap::Bitmap(void* address, int fd, size_t mappedSize, const SkImageInfo& info, size_t rowBytes)
@@ -266,9 +256,8 @@ Bitmap::Bitmap(AHardwareBuffer* buffer, const SkImageInfo& info, size_t rowBytes
Bitmap::~Bitmap() {
switch (mPixelStorageType) {
- case PixelStorageType::External:
- mPixelStorage.external.freeFunc(mPixelStorage.external.address,
- mPixelStorage.external.context);
+ case PixelStorageType::WrappedPixelRef:
+ mPixelStorage.wrapped.pixelRef->unref();
break;
case PixelStorageType::Ashmem:
#ifndef _WIN32 // ashmem not implemented on Windows
@@ -300,19 +289,6 @@ void Bitmap::setHasHardwareMipMap(bool hasMipMap) {
mHasHardwareMipMap = hasMipMap;
}
-void* Bitmap::getStorage() const {
- switch (mPixelStorageType) {
- case PixelStorageType::External:
- return mPixelStorage.external.address;
- case PixelStorageType::Ashmem:
- return mPixelStorage.ashmem.address;
- case PixelStorageType::Heap:
- return mPixelStorage.heap.address;
- case PixelStorageType::Hardware:
- return nullptr;
- }
-}
-
int Bitmap::getAshmemFd() const {
switch (mPixelStorageType) {
case PixelStorageType::Ashmem:
diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h
index b8b59947a57b..6ece7ef9f329 100644
--- a/libs/hwui/hwui/Bitmap.h
+++ b/libs/hwui/hwui/Bitmap.h
@@ -32,7 +32,7 @@ class SkWStream;
namespace android {
enum class PixelStorageType {
- External,
+ WrappedPixelRef,
Heap,
Ashmem,
Hardware,
@@ -56,7 +56,7 @@ class PixelStorage;
typedef void (*FreeFunc)(void* addr, void* context);
-class ANDROID_API Bitmap : public SkPixelRef {
+class Bitmap : public SkPixelRef {
public:
/* The allocate factories not only construct the Bitmap object but also allocate the
* backing store whose type is determined by the specific method that is called.
@@ -71,6 +71,7 @@ public:
static sk_sp<Bitmap> allocateHardwareBitmap(const SkBitmap& bitmap);
static sk_sp<Bitmap> allocateHeapBitmap(SkBitmap* bitmap);
static sk_sp<Bitmap> allocateHeapBitmap(const SkImageInfo& info);
+ static sk_sp<Bitmap> allocateHeapBitmap(size_t size, const SkImageInfo& i, size_t rowBytes);
/* The createFrom factories construct a new Bitmap object by wrapping the already allocated
* memory that is provided as an input param.
@@ -160,11 +161,9 @@ public:
int32_t quality, SkWStream* stream);
private:
static sk_sp<Bitmap> allocateAshmemBitmap(size_t size, const SkImageInfo& i, size_t rowBytes);
- static sk_sp<Bitmap> allocateHeapBitmap(size_t size, const SkImageInfo& i, size_t rowBytes);
Bitmap(void* address, size_t allocSize, const SkImageInfo& info, size_t rowBytes);
- Bitmap(void* address, void* context, FreeFunc freeFunc, const SkImageInfo& info,
- size_t rowBytes);
+ Bitmap(SkPixelRef& pixelRef, const SkImageInfo& info);
Bitmap(void* address, int fd, size_t mappedSize, const SkImageInfo& info, size_t rowBytes);
#ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
Bitmap(AHardwareBuffer* buffer, const SkImageInfo& info, size_t rowBytes,
@@ -178,7 +177,6 @@ private:
#endif
virtual ~Bitmap();
- void* getStorage() const;
SkImageInfo mInfo;
@@ -191,10 +189,8 @@ private:
union {
struct {
- void* address;
- void* context;
- FreeFunc freeFunc;
- } external;
+ SkPixelRef* pixelRef;
+ } wrapped;
struct {
void* address;
int fd;
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index 27dfed305a94..333567b0cf91 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -20,7 +20,6 @@
#include <utils/Functor.h>
#include <androidfw/ResourceTypes.h>
-#include "GlFunctorLifecycleListener.h"
#include "Properties.h"
#include "utils/Macros.h"
@@ -144,7 +143,7 @@ public:
virtual void resetRecording(int width, int height,
uirenderer::RenderNode* renderNode = nullptr) = 0;
virtual uirenderer::DisplayList* finishRecording() = 0;
- virtual void insertReorderBarrier(bool enableReorder) = 0;
+ virtual void enableZ(bool enableZ) = 0;
bool isHighContrastText() const { return uirenderer::Properties::enableHighContrastText; }
@@ -162,8 +161,7 @@ public:
virtual void drawLayer(uirenderer::DeferredLayerUpdater* layerHandle) = 0;
virtual void drawRenderNode(uirenderer::RenderNode* renderNode) = 0;
- virtual void callDrawGLFunction(Functor* functor,
- uirenderer::GlFunctorLifecycleListener* listener) = 0;
+
virtual void drawWebViewFunctor(int /*functor*/) {
LOG_ALWAYS_FATAL("Not supported");
}
diff --git a/libs/hwui/hwui/MinikinSkia.cpp b/libs/hwui/hwui/MinikinSkia.cpp
index 6a12a203b9f8..a6137b073d5a 100644
--- a/libs/hwui/hwui/MinikinSkia.cpp
+++ b/libs/hwui/hwui/MinikinSkia.cpp
@@ -125,22 +125,22 @@ const std::vector<minikin::FontVariation>& MinikinFontSkia::GetAxes() const {
std::shared_ptr<minikin::MinikinFont> MinikinFontSkia::createFontWithVariation(
const std::vector<minikin::FontVariation>& variations) const {
- SkFontArguments params;
+ SkFontArguments args;
int ttcIndex;
std::unique_ptr<SkStreamAsset> stream(mTypeface->openStream(&ttcIndex));
LOG_ALWAYS_FATAL_IF(stream == nullptr, "openStream failed");
- params.setCollectionIndex(ttcIndex);
- std::vector<SkFontArguments::Axis> skAxes;
- skAxes.resize(variations.size());
+ args.setCollectionIndex(ttcIndex);
+ std::vector<SkFontArguments::VariationPosition::Coordinate> skVariation;
+ skVariation.resize(variations.size());
for (size_t i = 0; i < variations.size(); i++) {
- skAxes[i].fTag = variations[i].axisTag;
- skAxes[i].fStyleValue = SkFloatToScalar(variations[i].value);
+ skVariation[i].axis = variations[i].axisTag;
+ skVariation[i].value = SkFloatToScalar(variations[i].value);
}
- params.setAxes(skAxes.data(), skAxes.size());
+ args.setVariationDesignPosition({skVariation.data(), static_cast<int>(skVariation.size())});
sk_sp<SkFontMgr> fm(SkFontMgr::RefDefault());
- sk_sp<SkTypeface> face(fm->makeFromStream(std::move(stream), params));
+ sk_sp<SkTypeface> face(fm->makeFromStream(std::move(stream), args));
return std::make_shared<MinikinFontSkia>(std::move(face), mFontData, mFontSize, mFilePath,
ttcIndex, variations);
diff --git a/libs/hwui/hwui/MinikinUtils.h b/libs/hwui/hwui/MinikinUtils.h
index cbf409504675..0eacde9a467e 100644
--- a/libs/hwui/hwui/MinikinUtils.h
+++ b/libs/hwui/hwui/MinikinUtils.h
@@ -39,30 +39,30 @@ namespace android {
class MinikinUtils {
public:
- ANDROID_API static minikin::MinikinPaint prepareMinikinPaint(const Paint* paint,
+ static minikin::MinikinPaint prepareMinikinPaint(const Paint* paint,
const Typeface* typeface);
- ANDROID_API static minikin::Layout doLayout(const Paint* paint, minikin::Bidi bidiFlags,
+ static minikin::Layout doLayout(const Paint* paint, minikin::Bidi bidiFlags,
const Typeface* typeface, const uint16_t* buf,
size_t bufSize, size_t start, size_t count,
size_t contextStart, size_t contextCount,
minikin::MeasuredText* mt);
- ANDROID_API static float measureText(const Paint* paint, minikin::Bidi bidiFlags,
+ static float measureText(const Paint* paint, minikin::Bidi bidiFlags,
const Typeface* typeface, const uint16_t* buf,
size_t start, size_t count, size_t bufSize,
float* advances);
- ANDROID_API static bool hasVariationSelector(const Typeface* typeface, uint32_t codepoint,
+ static bool hasVariationSelector(const Typeface* typeface, uint32_t codepoint,
uint32_t vs);
- ANDROID_API static float xOffsetForTextAlign(Paint* paint, const minikin::Layout& layout);
+ static float xOffsetForTextAlign(Paint* paint, const minikin::Layout& layout);
- ANDROID_API static float hOffsetForTextAlign(Paint* paint, const minikin::Layout& layout,
+ static float hOffsetForTextAlign(Paint* paint, const minikin::Layout& layout,
const SkPath& path);
// f is a functor of type void f(size_t start, size_t end);
template <typename F>
- ANDROID_API static void forFontRun(const minikin::Layout& layout, Paint* paint, F& f) {
+ static void forFontRun(const minikin::Layout& layout, Paint* paint, F& f) {
float saveSkewX = paint->getSkFont().getSkewX();
bool savefakeBold = paint->getSkFont().isEmbolden();
const minikin::MinikinFont* curFont = nullptr;
diff --git a/libs/hwui/hwui/Paint.h b/libs/hwui/hwui/Paint.h
index 281ecd27d780..e75e9e7c6933 100644
--- a/libs/hwui/hwui/Paint.h
+++ b/libs/hwui/hwui/Paint.h
@@ -32,7 +32,7 @@
namespace android {
-class ANDROID_API Paint : public SkPaint {
+class Paint : public SkPaint {
public:
// Default values for underlined and strikethrough text,
// as defined by Skia in SkTextFormatParams.h.
diff --git a/libs/hwui/jni/Bitmap.cpp b/libs/hwui/jni/Bitmap.cpp
index c0663a9bc699..eb9885a4436a 100755
--- a/libs/hwui/jni/Bitmap.cpp
+++ b/libs/hwui/jni/Bitmap.cpp
@@ -19,12 +19,19 @@
#include <utils/Color.h>
#ifdef __ANDROID__ // Layoutlib does not support graphic buffer, parcel or render thread
+#include <android-base/unique_fd.h>
+#include <android/binder_parcel.h>
+#include <android/binder_parcel_jni.h>
+#include <android/binder_parcel_platform.h>
+#include <android/binder_parcel_utils.h>
#include <private/android/AHardwareBufferHelpers.h>
-#include <binder/Parcel.h>
+#include <cutils/ashmem.h>
#include <dlfcn.h>
#include <renderthread/RenderProxy.h>
+#include <sys/mman.h>
#endif
+#include <inttypes.h>
#include <string.h>
#include <memory>
#include <string>
@@ -567,152 +574,296 @@ static void Bitmap_setHasMipMap(JNIEnv* env, jobject, jlong bitmapHandle,
///////////////////////////////////////////////////////////////////////////////
+// TODO: Move somewhere else
#ifdef __ANDROID__ // Layoutlib does not support parcel
-static struct parcel_offsets_t
-{
- jclass clazz;
- jfieldID mNativePtr;
-} gParcelOffsets;
-
-static Parcel* parcelForJavaObject(JNIEnv* env, jobject obj) {
- if (obj) {
- Parcel* p = (Parcel*)env->GetLongField(obj, gParcelOffsets.mNativePtr);
- if (p != NULL) {
- return p;
+
+class ScopedParcel {
+public:
+ explicit ScopedParcel(JNIEnv* env, jobject parcel) {
+ mParcel = AParcel_fromJavaParcel(env, parcel);
+ }
+
+ ~ScopedParcel() { AParcel_delete(mParcel); }
+
+ int32_t readInt32() {
+ int32_t temp = 0;
+ // TODO: This behavior-matches what android::Parcel does
+ // but this should probably be better
+ if (AParcel_readInt32(mParcel, &temp) != STATUS_OK) {
+ temp = 0;
}
- jniThrowException(env, "java/lang/IllegalStateException", "Parcel has been finalized!");
+ return temp;
+ }
+
+ uint32_t readUint32() {
+ uint32_t temp = 0;
+ // TODO: This behavior-matches what android::Parcel does
+ // but this should probably be better
+ if (AParcel_readUint32(mParcel, &temp) != STATUS_OK) {
+ temp = 0;
+ }
+ return temp;
+ }
+
+ void writeInt32(int32_t value) { AParcel_writeInt32(mParcel, value); }
+
+ void writeUint32(uint32_t value) { AParcel_writeUint32(mParcel, value); }
+
+ bool allowFds() const { return AParcel_getAllowFds(mParcel); }
+
+ std::optional<sk_sp<SkData>> readData() {
+ struct Data {
+ void* ptr = nullptr;
+ size_t size = 0;
+ } data;
+ auto error = AParcel_readByteArray(mParcel, &data,
+ [](void* arrayData, int32_t length,
+ int8_t** outBuffer) -> bool {
+ Data* data = reinterpret_cast<Data*>(arrayData);
+ if (length > 0) {
+ data->ptr = sk_malloc_canfail(length);
+ if (!data->ptr) {
+ return false;
+ }
+ *outBuffer =
+ reinterpret_cast<int8_t*>(data->ptr);
+ data->size = length;
+ }
+ return true;
+ });
+ if (error != STATUS_OK || data.size <= 0) {
+ sk_free(data.ptr);
+ return std::nullopt;
+ } else {
+ return SkData::MakeFromMalloc(data.ptr, data.size);
+ }
+ }
+
+ void writeData(const std::optional<sk_sp<SkData>>& optData) {
+ if (optData) {
+ const auto& data = *optData;
+ AParcel_writeByteArray(mParcel, reinterpret_cast<const int8_t*>(data->data()),
+ data->size());
+ } else {
+ AParcel_writeByteArray(mParcel, nullptr, -1);
+ }
+ }
+
+ AParcel* get() { return mParcel; }
+
+private:
+ AParcel* mParcel;
+};
+
+enum class BlobType : int32_t {
+ IN_PLACE,
+ ASHMEM,
+};
+
+#define ON_ERROR_RETURN(X) \
+ if ((error = (X)) != STATUS_OK) return error
+
+template <typename T, typename U>
+static binder_status_t readBlob(AParcel* parcel, T inPlaceCallback, U ashmemCallback) {
+ binder_status_t error = STATUS_OK;
+ BlobType type;
+ static_assert(sizeof(BlobType) == sizeof(int32_t));
+ ON_ERROR_RETURN(AParcel_readInt32(parcel, (int32_t*)&type));
+ if (type == BlobType::IN_PLACE) {
+ struct Data {
+ std::unique_ptr<int8_t[]> ptr = nullptr;
+ int32_t size = 0;
+ } data;
+ ON_ERROR_RETURN(
+ AParcel_readByteArray(parcel, &data,
+ [](void* arrayData, int32_t length, int8_t** outBuffer) {
+ Data* data = reinterpret_cast<Data*>(arrayData);
+ if (length > 0) {
+ data->ptr = std::make_unique<int8_t[]>(length);
+ data->size = length;
+ *outBuffer = data->ptr.get();
+ }
+ return data->ptr != nullptr;
+ }));
+ inPlaceCallback(std::move(data.ptr), data.size);
+ return STATUS_OK;
+ } else if (type == BlobType::ASHMEM) {
+ int rawFd = -1;
+ int32_t size = 0;
+ ON_ERROR_RETURN(AParcel_readInt32(parcel, &size));
+ ON_ERROR_RETURN(AParcel_readParcelFileDescriptor(parcel, &rawFd));
+ android::base::unique_fd fd(rawFd);
+ ashmemCallback(std::move(fd), size);
+ return STATUS_OK;
+ } else {
+ // Although the above if/else was "exhaustive" guard against unknown types
+ return STATUS_UNKNOWN_ERROR;
}
- return NULL;
}
-#endif
+
+static constexpr size_t BLOB_INPLACE_LIMIT = 12 * 1024;
+// Fail fast if we can't use ashmem and the size exceeds this limit - the binder transaction
+// wouldn't go through, anyway
+// TODO: Can we get this from somewhere?
+static constexpr size_t BLOB_MAX_INPLACE_LIMIT = 1 * 1024 * 1024;
+static constexpr bool shouldUseAshmem(AParcel* parcel, int32_t size) {
+ return size > BLOB_INPLACE_LIMIT && AParcel_getAllowFds(parcel);
+}
+
+static binder_status_t writeBlobFromFd(AParcel* parcel, int32_t size, int fd) {
+ binder_status_t error = STATUS_OK;
+ ON_ERROR_RETURN(AParcel_writeInt32(parcel, static_cast<int32_t>(BlobType::ASHMEM)));
+ ON_ERROR_RETURN(AParcel_writeInt32(parcel, size));
+ ON_ERROR_RETURN(AParcel_writeParcelFileDescriptor(parcel, fd));
+ return STATUS_OK;
+}
+
+static binder_status_t writeBlob(AParcel* parcel, const int32_t size, const void* data, bool immutable) {
+ if (size <= 0 || data == nullptr) {
+ return STATUS_NOT_ENOUGH_DATA;
+ }
+ binder_status_t error = STATUS_OK;
+ if (shouldUseAshmem(parcel, size)) {
+ // Create new ashmem region with read/write priv
+ base::unique_fd fd(ashmem_create_region("bitmap", size));
+ if (fd.get() < 0) {
+ return STATUS_NO_MEMORY;
+ }
+
+ {
+ void* dest = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd.get(), 0);
+ if (dest == MAP_FAILED) {
+ return STATUS_NO_MEMORY;
+ }
+ memcpy(dest, data, size);
+ munmap(dest, size);
+ }
+
+ if (immutable && ashmem_set_prot_region(fd.get(), PROT_READ) < 0) {
+ return STATUS_UNKNOWN_ERROR;
+ }
+ // Workaround b/149851140 in AParcel_writeParcelFileDescriptor
+ int rawFd = fd.release();
+ error = writeBlobFromFd(parcel, size, rawFd);
+ close(rawFd);
+ return error;
+ } else {
+ if (size > BLOB_MAX_INPLACE_LIMIT) {
+ return STATUS_FAILED_TRANSACTION;
+ }
+ ON_ERROR_RETURN(AParcel_writeInt32(parcel, static_cast<int32_t>(BlobType::IN_PLACE)));
+ ON_ERROR_RETURN(AParcel_writeByteArray(parcel, static_cast<const int8_t*>(data), size));
+ return STATUS_OK;
+ }
+}
+
+#undef ON_ERROR_RETURN
+
+#endif // __ANDROID__ // Layoutlib does not support parcel
// This is the maximum possible size because the SkColorSpace must be
// representable (and therefore serializable) using a matrix and numerical
// transfer function. If we allow more color space representations in the
// framework, we may need to update this maximum size.
-static constexpr uint32_t kMaxColorSpaceSerializedBytes = 80;
+static constexpr size_t kMaxColorSpaceSerializedBytes = 80;
+
+static constexpr auto RuntimeException = "java/lang/RuntimeException";
+
+static bool validateImageInfo(const SkImageInfo& info, int32_t rowBytes) {
+ // TODO: Can we avoid making a SkBitmap for this?
+ return SkBitmap().setInfo(info, rowBytes);
+}
static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) {
#ifdef __ANDROID__ // Layoutlib does not support parcel
if (parcel == NULL) {
- SkDebugf("-------- unparcel parcel is NULL\n");
+ jniThrowNullPointerException(env, "parcel cannot be null");
return NULL;
}
- android::Parcel* p = parcelForJavaObject(env, parcel);
+ ScopedParcel p(env, parcel);
- const bool isMutable = p->readInt32() != 0;
- const SkColorType colorType = (SkColorType)p->readInt32();
- const SkAlphaType alphaType = (SkAlphaType)p->readInt32();
- const uint32_t colorSpaceSize = p->readUint32();
+ const bool isMutable = p.readInt32();
+ const SkColorType colorType = static_cast<SkColorType>(p.readInt32());
+ const SkAlphaType alphaType = static_cast<SkAlphaType>(p.readInt32());
sk_sp<SkColorSpace> colorSpace;
- if (colorSpaceSize > 0) {
- if (colorSpaceSize > kMaxColorSpaceSerializedBytes) {
+ const auto optColorSpaceData = p.readData();
+ if (optColorSpaceData) {
+ const auto& colorSpaceData = *optColorSpaceData;
+ if (colorSpaceData->size() > kMaxColorSpaceSerializedBytes) {
ALOGD("Bitmap_createFromParcel: Serialized SkColorSpace is larger than expected: "
- "%d bytes\n", colorSpaceSize);
+ "%zu bytes (max: %zu)\n",
+ colorSpaceData->size(), kMaxColorSpaceSerializedBytes);
}
- const void* data = p->readInplace(colorSpaceSize);
- if (data) {
- colorSpace = SkColorSpace::Deserialize(data, colorSpaceSize);
- } else {
- ALOGD("Bitmap_createFromParcel: Unable to read serialized SkColorSpace data\n");
- }
+ colorSpace = SkColorSpace::Deserialize(colorSpaceData->data(), colorSpaceData->size());
}
- const int width = p->readInt32();
- const int height = p->readInt32();
- const int rowBytes = p->readInt32();
- const int density = p->readInt32();
+ const int32_t width = p.readInt32();
+ const int32_t height = p.readInt32();
+ const int32_t rowBytes = p.readInt32();
+ const int32_t density = p.readInt32();
if (kN32_SkColorType != colorType &&
kRGBA_F16_SkColorType != colorType &&
kRGB_565_SkColorType != colorType &&
kARGB_4444_SkColorType != colorType &&
kAlpha_8_SkColorType != colorType) {
- SkDebugf("Bitmap_createFromParcel unknown colortype: %d\n", colorType);
+ jniThrowExceptionFmt(env, RuntimeException,
+ "Bitmap_createFromParcel unknown colortype: %d\n", colorType);
return NULL;
}
- std::unique_ptr<SkBitmap> bitmap(new SkBitmap);
- if (!bitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType, colorSpace),
- rowBytes)) {
+ auto imageInfo = SkImageInfo::Make(width, height, colorType, alphaType, colorSpace);
+ size_t allocationSize = 0;
+ if (!validateImageInfo(imageInfo, rowBytes)) {
+ jniThrowRuntimeException(env, "Received bad SkImageInfo");
return NULL;
}
-
- // Read the bitmap blob.
- size_t size = bitmap->computeByteSize();
- android::Parcel::ReadableBlob blob;
- android::status_t status = p->readBlob(size, &blob);
- if (status) {
- doThrowRE(env, "Could not read bitmap blob.");
+ if (!Bitmap::computeAllocationSize(rowBytes, height, &allocationSize)) {
+ jniThrowExceptionFmt(env, RuntimeException,
+ "Received bad bitmap size: width=%d, height=%d, rowBytes=%d", width,
+ height, rowBytes);
return NULL;
}
-
- // Map the bitmap in place from the ashmem region if possible otherwise copy.
sk_sp<Bitmap> nativeBitmap;
- // If the blob is mutable we have ownership of the region and can always use it
- // If the blob is immutable _and_ we're immutable, we can then still use it
- if (blob.fd() >= 0 && (blob.isMutable() || !isMutable)) {
-#if DEBUG_PARCEL
- ALOGD("Bitmap.createFromParcel: mapped contents of bitmap from %s blob "
- "(fds %s)",
- blob.isMutable() ? "mutable" : "immutable",
- p->allowFds() ? "allowed" : "forbidden");
-#endif
- // Dup the file descriptor so we can keep a reference to it after the Parcel
- // is disposed.
- int dupFd = fcntl(blob.fd(), F_DUPFD_CLOEXEC, 0);
- if (dupFd < 0) {
- ALOGE("Error allocating dup fd. Error:%d", errno);
- blob.release();
- doThrowRE(env, "Could not allocate dup blob fd.");
- return NULL;
- }
-
- // Map the pixels in place and take ownership of the ashmem region. We must also respect the
- // rowBytes value already set on the bitmap instead of attempting to compute our own.
- nativeBitmap = Bitmap::createFrom(bitmap->info(), bitmap->rowBytes(), dupFd,
- const_cast<void*>(blob.data()), size, !isMutable);
- if (!nativeBitmap) {
- close(dupFd);
- blob.release();
- doThrowRE(env, "Could not allocate ashmem pixel ref.");
- return NULL;
- }
-
- // Clear the blob handle, don't release it.
- blob.clear();
- } else {
-#if DEBUG_PARCEL
- if (blob.fd() >= 0) {
- ALOGD("Bitmap.createFromParcel: copied contents of mutable bitmap "
- "from immutable blob (fds %s)",
- p->allowFds() ? "allowed" : "forbidden");
- } else {
- ALOGD("Bitmap.createFromParcel: copied contents from %s blob "
- "(fds %s)",
- blob.isMutable() ? "mutable" : "immutable",
- p->allowFds() ? "allowed" : "forbidden");
- }
-#endif
-
- // Copy the pixels into a new buffer.
- nativeBitmap = Bitmap::allocateHeapBitmap(bitmap.get());
- if (!nativeBitmap) {
- blob.release();
- doThrowRE(env, "Could not allocate java pixel ref.");
- return NULL;
- }
- memcpy(bitmap->getPixels(), blob.data(), size);
-
- // Release the blob handle.
- blob.release();
+ binder_status_t error = readBlob(
+ p.get(),
+ // In place callback
+ [&](std::unique_ptr<int8_t[]> buffer, int32_t size) {
+ nativeBitmap = Bitmap::allocateHeapBitmap(allocationSize, imageInfo, rowBytes);
+ if (nativeBitmap) {
+ memcpy(nativeBitmap->pixels(), buffer.get(), size);
+ }
+ },
+ // Ashmem callback
+ [&](android::base::unique_fd fd, int32_t size) {
+ int flags = PROT_READ;
+ if (isMutable) {
+ flags |= PROT_WRITE;
+ }
+ void* addr = mmap(nullptr, size, flags, MAP_SHARED, fd.get(), 0);
+ if (addr == MAP_FAILED) {
+ const int err = errno;
+ ALOGW("mmap failed, error %d (%s)", err, strerror(err));
+ return;
+ }
+ nativeBitmap =
+ Bitmap::createFrom(imageInfo, rowBytes, fd.release(), addr, size, !isMutable);
+ });
+ if (error != STATUS_OK) {
+ // TODO: Stringify the error, see signalExceptionForError in android_util_Binder.cpp
+ jniThrowExceptionFmt(env, RuntimeException, "Failed to read from Parcel, error=%d", error);
+ return nullptr;
+ }
+ if (!nativeBitmap) {
+ jniThrowRuntimeException(env, "Could not allocate java pixel ref.");
+ return nullptr;
}
- return createBitmap(env, nativeBitmap.release(),
- getPremulBitmapCreateFlags(isMutable), NULL, NULL, density);
+ return createBitmap(env, nativeBitmap.release(), getPremulBitmapCreateFlags(isMutable), nullptr,
+ nullptr, density);
#else
- doThrowRE(env, "Cannot use parcels outside of Android");
+ jniThrowRuntimeException(env, "Cannot use parcels outside of Android");
return NULL;
#endif
}
@@ -725,48 +876,38 @@ static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject,
return JNI_FALSE;
}
- android::Parcel* p = parcelForJavaObject(env, parcel);
+ ScopedParcel p(env, parcel);
SkBitmap bitmap;
auto bitmapWrapper = reinterpret_cast<BitmapWrapper*>(bitmapHandle);
bitmapWrapper->getSkBitmap(&bitmap);
- p->writeInt32(!bitmap.isImmutable());
- p->writeInt32(bitmap.colorType());
- p->writeInt32(bitmap.alphaType());
+ p.writeInt32(!bitmap.isImmutable());
+ p.writeInt32(bitmap.colorType());
+ p.writeInt32(bitmap.alphaType());
SkColorSpace* colorSpace = bitmap.colorSpace();
if (colorSpace != nullptr) {
- sk_sp<SkData> data = colorSpace->serialize();
- size_t size = data->size();
- p->writeUint32(size);
- if (size > 0) {
- if (size > kMaxColorSpaceSerializedBytes) {
- ALOGD("Bitmap_writeToParcel: Serialized SkColorSpace is larger than expected: "
- "%zu bytes\n", size);
- }
-
- p->write(data->data(), size);
- }
+ p.writeData(colorSpace->serialize());
} else {
- p->writeUint32(0);
+ p.writeData(std::nullopt);
}
- p->writeInt32(bitmap.width());
- p->writeInt32(bitmap.height());
- p->writeInt32(bitmap.rowBytes());
- p->writeInt32(density);
+ p.writeInt32(bitmap.width());
+ p.writeInt32(bitmap.height());
+ p.writeInt32(bitmap.rowBytes());
+ p.writeInt32(density);
// Transfer the underlying ashmem region if we have one and it's immutable.
- android::status_t status;
+ binder_status_t status;
int fd = bitmapWrapper->bitmap().getAshmemFd();
- if (fd >= 0 && bitmap.isImmutable() && p->allowFds()) {
+ if (fd >= 0 && p.allowFds() && bitmap.isImmutable()) {
#if DEBUG_PARCEL
ALOGD("Bitmap.writeToParcel: transferring immutable bitmap's ashmem fd as "
- "immutable blob (fds %s)",
- p->allowFds() ? "allowed" : "forbidden");
+ "immutable blob (fds %s)",
+ p.allowFds() ? "allowed" : "forbidden");
#endif
- status = p->writeDupImmutableBlobFileDescriptor(fd);
- if (status) {
+ status = writeBlobFromFd(p.get(), bitmapWrapper->bitmap().getAllocationByteCount(), fd);
+ if (status != STATUS_OK) {
doThrowRE(env, "Could not write bitmap blob file descriptor.");
return JNI_FALSE;
}
@@ -776,26 +917,15 @@ static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject,
// Copy the bitmap to a new blob.
#if DEBUG_PARCEL
ALOGD("Bitmap.writeToParcel: copying bitmap into new blob (fds %s)",
- p->allowFds() ? "allowed" : "forbidden");
+ p.allowFds() ? "allowed" : "forbidden");
#endif
- const bool mutableCopy = !bitmap.isImmutable();
size_t size = bitmap.computeByteSize();
- android::Parcel::WritableBlob blob;
- status = p->writeBlob(size, mutableCopy, &blob);
+ status = writeBlob(p.get(), size, bitmap.getPixels(), bitmap.isImmutable());
if (status) {
doThrowRE(env, "Could not copy bitmap to parcel blob.");
return JNI_FALSE;
}
-
- const void* pSrc = bitmap.getPixels();
- if (pSrc == NULL) {
- memset(blob.data(), 0, size);
- } else {
- memcpy(blob.data(), pSrc, size);
- }
-
- blob.release();
return JNI_TRUE;
#else
doThrowRE(env, "Cannot use parcels outside of Android");
@@ -1074,13 +1204,16 @@ static jobject Bitmap_wrapHardwareBufferBitmap(JNIEnv* env, jobject, jobject har
static jobject Bitmap_getHardwareBuffer(JNIEnv* env, jobject, jlong bitmapPtr) {
#ifdef __ANDROID__ // Layoutlib does not support graphic buffer
LocalScopedBitmap bitmapHandle(bitmapPtr);
- LOG_ALWAYS_FATAL_IF(!bitmapHandle->isHardware(),
+ if (!bitmapHandle->isHardware()) {
+ jniThrowException(env, "java/lang/IllegalStateException",
"Hardware config is only supported config in Bitmap_getHardwareBuffer");
+ return nullptr;
+ }
Bitmap& bitmap = bitmapHandle->bitmap();
return AHardwareBuffer_toHardwareBuffer(env, bitmap.hardwareBuffer());
#else
- return NULL;
+ return nullptr;
#endif
}
@@ -1091,6 +1224,14 @@ static jboolean Bitmap_isImmutable(CRITICAL_JNI_PARAMS_COMMA jlong bitmapHandle)
return bitmapHolder->bitmap().isImmutable() ? JNI_TRUE : JNI_FALSE;
}
+static jboolean Bitmap_isBackedByAshmem(CRITICAL_JNI_PARAMS_COMMA jlong bitmapHandle) {
+ LocalScopedBitmap bitmapHolder(bitmapHandle);
+ if (!bitmapHolder.valid()) return JNI_FALSE;
+
+ return bitmapHolder->bitmap().pixelStorageType() == PixelStorageType::Ashmem ? JNI_TRUE
+ : JNI_FALSE;
+}
+
static void Bitmap_setImmutable(JNIEnv* env, jobject, jlong bitmapHandle) {
LocalScopedBitmap bitmapHolder(bitmapHandle);
if (!bitmapHolder.valid()) return;
@@ -1157,12 +1298,11 @@ static const JNINativeMethod gBitmapMethods[] = {
{ "nativeSetImmutable", "(J)V", (void*)Bitmap_setImmutable},
// ------------ @CriticalNative ----------------
- { "nativeIsImmutable", "(J)Z", (void*)Bitmap_isImmutable}
+ { "nativeIsImmutable", "(J)Z", (void*)Bitmap_isImmutable},
+ { "nativeIsBackedByAshmem", "(J)Z", (void*)Bitmap_isBackedByAshmem}
};
-const char* const kParcelPathName = "android/os/Parcel";
-
int register_android_graphics_Bitmap(JNIEnv* env)
{
gBitmap_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Bitmap"));
@@ -1180,9 +1320,6 @@ int register_android_graphics_Bitmap(JNIEnv* env)
AHardwareBuffer_toHardwareBuffer = (AHB_to_HB)dlsym(handle_, "AHardwareBuffer_toHardwareBuffer");
LOG_ALWAYS_FATAL_IF(AHardwareBuffer_toHardwareBuffer == nullptr,
" Failed to find required symbol AHardwareBuffer_toHardwareBuffer!");
-
- gParcelOffsets.clazz = MakeGlobalRefOrDie(env, FindClassOrDie(env, kParcelPathName));
- gParcelOffsets.mNativePtr = GetFieldIDOrDie(env, gParcelOffsets.clazz, "mNativePtr", "J");
#endif
return android::RegisterMethodsOrDie(env, "android/graphics/Bitmap", gBitmapMethods,
NELEM(gBitmapMethods));
diff --git a/libs/hwui/jni/BitmapFactory.cpp b/libs/hwui/jni/BitmapFactory.cpp
index e8e89d81bdb7..7d2583a2ac01 100644
--- a/libs/hwui/jni/BitmapFactory.cpp
+++ b/libs/hwui/jni/BitmapFactory.cpp
@@ -3,12 +3,11 @@
#include "BitmapFactory.h"
#include "CreateJavaOutputStreamAdaptor.h"
+#include "FrontBufferedStream.h"
#include "GraphicsJNI.h"
#include "MimeType.h"
#include "NinePatchPeeker.h"
#include "SkAndroidCodec.h"
-#include "SkBRDAllocator.h"
-#include "SkFrontBufferedStream.h"
#include "SkMath.h"
#include "SkPixelRef.h"
#include "SkStream.h"
@@ -510,8 +509,8 @@ static jobject nativeDecodeStream(JNIEnv* env, jobject clazz, jobject is, jbyteA
std::unique_ptr<SkStream> stream(CreateJavaInputStreamAdaptor(env, is, storage));
if (stream.get()) {
- std::unique_ptr<SkStreamRewindable> bufferedStream(
- SkFrontBufferedStream::Make(std::move(stream), SkCodec::MinBufferedBytesNeeded()));
+ std::unique_ptr<SkStreamRewindable> bufferedStream(skia::FrontBufferedStream::Make(
+ std::move(stream), SkCodec::MinBufferedBytesNeeded()));
SkASSERT(bufferedStream.get() != NULL);
bitmap = doDecode(env, std::move(bufferedStream), padding, options, inBitmapHandle,
colorSpaceHandle);
@@ -565,8 +564,8 @@ static jobject nativeDecodeFileDescriptor(JNIEnv* env, jobject clazz, jobject fi
// Use a buffered stream. Although an SkFILEStream can be rewound, this
// ensures that SkImageDecoder::Factory never rewinds beyond the
// current position of the file descriptor.
- std::unique_ptr<SkStreamRewindable> stream(SkFrontBufferedStream::Make(std::move(fileStream),
- SkCodec::MinBufferedBytesNeeded()));
+ std::unique_ptr<SkStreamRewindable> stream(skia::FrontBufferedStream::Make(
+ std::move(fileStream), SkCodec::MinBufferedBytesNeeded()));
return doDecode(env, std::move(stream), padding, bitmapFactoryOptions, inBitmapHandle,
colorSpaceHandle);
diff --git a/libs/hwui/jni/BitmapRegionDecoder.cpp b/libs/hwui/jni/BitmapRegionDecoder.cpp
index 712351382d97..4cc05ef6f13b 100644
--- a/libs/hwui/jni/BitmapRegionDecoder.cpp
+++ b/libs/hwui/jni/BitmapRegionDecoder.cpp
@@ -22,8 +22,8 @@
#include "GraphicsJNI.h"
#include "Utils.h"
+#include "BitmapRegionDecoder.h"
#include "SkBitmap.h"
-#include "SkBitmapRegionDecoder.h"
#include "SkCodec.h"
#include "SkData.h"
#include "SkStream.h"
@@ -36,10 +36,8 @@
using namespace android;
-static jobject createBitmapRegionDecoder(JNIEnv* env, std::unique_ptr<SkStreamRewindable> stream) {
- std::unique_ptr<SkBitmapRegionDecoder> brd(
- SkBitmapRegionDecoder::Create(stream.release(),
- SkBitmapRegionDecoder::kAndroidCodec_Strategy));
+static jobject createBitmapRegionDecoder(JNIEnv* env, sk_sp<SkData> data) {
+ auto brd = skia::BitmapRegionDecoder::Make(std::move(data));
if (!brd) {
doThrowIOE(env, "Image format not supported");
return nullObjectReturn("CreateBitmapRegionDecoder returned null");
@@ -49,21 +47,13 @@ static jobject createBitmapRegionDecoder(JNIEnv* env, std::unique_ptr<SkStreamRe
}
static jobject nativeNewInstanceFromByteArray(JNIEnv* env, jobject, jbyteArray byteArray,
- jint offset, jint length, jboolean isShareable) {
- /* If isShareable we could decide to just wrap the java array and
- share it, but that means adding a globalref to the java array object
- For now we just always copy the array's data if isShareable.
- */
+ jint offset, jint length) {
AutoJavaByteArray ar(env, byteArray);
- std::unique_ptr<SkMemoryStream> stream(new SkMemoryStream(ar.ptr() + offset, length, true));
-
- // the decoder owns the stream.
- jobject brd = createBitmapRegionDecoder(env, std::move(stream));
- return brd;
+ return createBitmapRegionDecoder(env, SkData::MakeWithCopy(ar.ptr() + offset, length));
}
static jobject nativeNewInstanceFromFileDescriptor(JNIEnv* env, jobject clazz,
- jobject fileDescriptor, jboolean isShareable) {
+ jobject fileDescriptor) {
NPE_CHECK_RETURN_ZERO(env, fileDescriptor);
jint descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor);
@@ -74,41 +64,28 @@ static jobject nativeNewInstanceFromFileDescriptor(JNIEnv* env, jobject clazz,
return nullObjectReturn("fstat return -1");
}
- sk_sp<SkData> data(SkData::MakeFromFD(descriptor));
- std::unique_ptr<SkMemoryStream> stream(new SkMemoryStream(std::move(data)));
-
- // the decoder owns the stream.
- jobject brd = createBitmapRegionDecoder(env, std::move(stream));
- return brd;
+ return createBitmapRegionDecoder(env, SkData::MakeFromFD(descriptor));
}
-static jobject nativeNewInstanceFromStream(JNIEnv* env, jobject clazz,
- jobject is, // InputStream
- jbyteArray storage, // byte[]
- jboolean isShareable) {
- jobject brd = NULL;
- // for now we don't allow shareable with java inputstreams
- std::unique_ptr<SkStreamRewindable> stream(CopyJavaInputStream(env, is, storage));
-
- if (stream) {
- // the decoder owns the stream.
- brd = createBitmapRegionDecoder(env, std::move(stream));
+static jobject nativeNewInstanceFromStream(JNIEnv* env, jobject clazz, jobject is, // InputStream
+ jbyteArray storage) { // byte[]
+ jobject brd = nullptr;
+ sk_sp<SkData> data = CopyJavaInputStream(env, is, storage);
+
+ if (data) {
+ brd = createBitmapRegionDecoder(env, std::move(data));
}
return brd;
}
-static jobject nativeNewInstanceFromAsset(JNIEnv* env, jobject clazz,
- jlong native_asset, // Asset
- jboolean isShareable) {
+static jobject nativeNewInstanceFromAsset(JNIEnv* env, jobject clazz, jlong native_asset) {
Asset* asset = reinterpret_cast<Asset*>(native_asset);
- std::unique_ptr<SkMemoryStream> stream(CopyAssetToStream(asset));
- if (NULL == stream) {
- return NULL;
+ sk_sp<SkData> data = CopyAssetToData(asset);
+ if (!data) {
+ return nullptr;
}
- // the decoder owns the stream.
- jobject brd = createBitmapRegionDecoder(env, std::move(stream));
- return brd;
+ return createBitmapRegionDecoder(env, data);
}
/*
@@ -158,7 +135,7 @@ static jobject nativeDecodeRegion(JNIEnv* env, jobject, jlong brdHandle, jint in
recycledBytes = recycledBitmap->getAllocationByteCount();
}
- SkBitmapRegionDecoder* brd = reinterpret_cast<SkBitmapRegionDecoder*>(brdHandle);
+ auto* brd = reinterpret_cast<skia::BitmapRegionDecoder*>(brdHandle);
SkColorType decodeColorType = brd->computeOutputColorType(colorType);
if (decodeColorType == kRGBA_F16_SkColorType && isHardware &&
!uirenderer::HardwareBitmapUploader::hasFP16Support()) {
@@ -166,7 +143,7 @@ static jobject nativeDecodeRegion(JNIEnv* env, jobject, jlong brdHandle, jint in
}
// Set up the pixel allocator
- SkBRDAllocator* allocator = nullptr;
+ skia::BRDAllocator* allocator = nullptr;
RecyclingClippingPixelAllocator recycleAlloc(recycledBitmap, recycledBytes);
HeapAllocator heapAlloc;
if (javaBitmap) {
@@ -230,20 +207,17 @@ static jobject nativeDecodeRegion(JNIEnv* env, jobject, jlong brdHandle, jint in
}
static jint nativeGetHeight(JNIEnv* env, jobject, jlong brdHandle) {
- SkBitmapRegionDecoder* brd =
- reinterpret_cast<SkBitmapRegionDecoder*>(brdHandle);
+ auto* brd = reinterpret_cast<skia::BitmapRegionDecoder*>(brdHandle);
return static_cast<jint>(brd->height());
}
static jint nativeGetWidth(JNIEnv* env, jobject, jlong brdHandle) {
- SkBitmapRegionDecoder* brd =
- reinterpret_cast<SkBitmapRegionDecoder*>(brdHandle);
+ auto* brd = reinterpret_cast<skia::BitmapRegionDecoder*>(brdHandle);
return static_cast<jint>(brd->width());
}
static void nativeClean(JNIEnv* env, jobject, jlong brdHandle) {
- SkBitmapRegionDecoder* brd =
- reinterpret_cast<SkBitmapRegionDecoder*>(brdHandle);
+ auto* brd = reinterpret_cast<skia::BitmapRegionDecoder*>(brdHandle);
delete brd;
}
@@ -261,22 +235,22 @@ static const JNINativeMethod gBitmapRegionDecoderMethods[] = {
{ "nativeClean", "(J)V", (void*)nativeClean},
{ "nativeNewInstance",
- "([BIIZ)Landroid/graphics/BitmapRegionDecoder;",
+ "([BII)Landroid/graphics/BitmapRegionDecoder;",
(void*)nativeNewInstanceFromByteArray
},
{ "nativeNewInstance",
- "(Ljava/io/InputStream;[BZ)Landroid/graphics/BitmapRegionDecoder;",
+ "(Ljava/io/InputStream;[B)Landroid/graphics/BitmapRegionDecoder;",
(void*)nativeNewInstanceFromStream
},
{ "nativeNewInstance",
- "(Ljava/io/FileDescriptor;Z)Landroid/graphics/BitmapRegionDecoder;",
+ "(Ljava/io/FileDescriptor;)Landroid/graphics/BitmapRegionDecoder;",
(void*)nativeNewInstanceFromFileDescriptor
},
{ "nativeNewInstance",
- "(JZ)Landroid/graphics/BitmapRegionDecoder;",
+ "(J)Landroid/graphics/BitmapRegionDecoder;",
(void*)nativeNewInstanceFromAsset
},
};
diff --git a/libs/hwui/jni/CreateJavaOutputStreamAdaptor.cpp b/libs/hwui/jni/CreateJavaOutputStreamAdaptor.cpp
index f1c6b29204b2..785a5dc995ab 100644
--- a/libs/hwui/jni/CreateJavaOutputStreamAdaptor.cpp
+++ b/libs/hwui/jni/CreateJavaOutputStreamAdaptor.cpp
@@ -177,8 +177,12 @@ SkStream* CreateJavaInputStreamAdaptor(JNIEnv* env, jobject stream, jbyteArray s
return JavaInputStreamAdaptor::Create(env, stream, storage, swallowExceptions);
}
-static SkMemoryStream* adaptor_to_mem_stream(SkStream* stream) {
- SkASSERT(stream != NULL);
+sk_sp<SkData> CopyJavaInputStream(JNIEnv* env, jobject inputStream, jbyteArray storage) {
+ std::unique_ptr<SkStream> stream(CreateJavaInputStreamAdaptor(env, inputStream, storage));
+ if (!stream) {
+ return nullptr;
+ }
+
size_t bufferSize = 4096;
size_t streamLen = 0;
size_t len;
@@ -194,18 +198,7 @@ static SkMemoryStream* adaptor_to_mem_stream(SkStream* stream) {
}
data = (char*)sk_realloc_throw(data, streamLen);
- SkMemoryStream* streamMem = new SkMemoryStream();
- streamMem->setMemoryOwned(data, streamLen);
- return streamMem;
-}
-
-SkStreamRewindable* CopyJavaInputStream(JNIEnv* env, jobject stream,
- jbyteArray storage) {
- std::unique_ptr<SkStream> adaptor(CreateJavaInputStreamAdaptor(env, stream, storage));
- if (NULL == adaptor.get()) {
- return NULL;
- }
- return adaptor_to_mem_stream(adaptor.get());
+ return SkData::MakeFromMalloc(data, streamLen);
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/jni/CreateJavaOutputStreamAdaptor.h b/libs/hwui/jni/CreateJavaOutputStreamAdaptor.h
index 849418da01a1..bae40f1e8d2f 100644
--- a/libs/hwui/jni/CreateJavaOutputStreamAdaptor.h
+++ b/libs/hwui/jni/CreateJavaOutputStreamAdaptor.h
@@ -2,6 +2,7 @@
#define _ANDROID_GRAPHICS_CREATE_JAVA_OUTPUT_STREAM_ADAPTOR_H_
#include "jni.h"
+#include "SkData.h"
class SkMemoryStream;
class SkStream;
@@ -27,15 +28,14 @@ SkStream* CreateJavaInputStreamAdaptor(JNIEnv* env, jobject stream, jbyteArray s
bool swallowExceptions = true);
/**
- * Copy a Java InputStream. The result will be rewindable.
+ * Copy a Java InputStream to an SkData.
* @param env JNIEnv object.
* @param stream Pointer to Java InputStream.
* @param storage Java byte array for retrieving data from the
* Java InputStream.
- * @return SkStreamRewindable The data in stream will be copied
- * to a new SkStreamRewindable.
+ * @return SkData containing the stream's data.
*/
-SkStreamRewindable* CopyJavaInputStream(JNIEnv* env, jobject stream, jbyteArray storage);
+sk_sp<SkData> CopyJavaInputStream(JNIEnv* env, jobject stream, jbyteArray storage);
SkWStream* CreateJavaOutputStreamAdaptor(JNIEnv* env, jobject stream, jbyteArray storage);
diff --git a/libs/hwui/jni/FontFamily.cpp b/libs/hwui/jni/FontFamily.cpp
index a2fef1e19328..68eaa0a3ca54 100644
--- a/libs/hwui/jni/FontFamily.cpp
+++ b/libs/hwui/jni/FontFamily.cpp
@@ -104,21 +104,21 @@ static jlong FontFamily_getFamilyReleaseFunc(CRITICAL_JNI_PARAMS) {
static bool addSkTypeface(NativeFamilyBuilder* builder, sk_sp<SkData>&& data, int ttcIndex,
jint weight, jint italic) {
- FatVector<SkFontArguments::Axis, 2> skiaAxes;
+ FatVector<SkFontArguments::VariationPosition::Coordinate, 2> skVariation;
for (const auto& axis : builder->axes) {
- skiaAxes.emplace_back(SkFontArguments::Axis{axis.axisTag, axis.value});
+ skVariation.push_back({axis.axisTag, axis.value});
}
const size_t fontSize = data->size();
const void* fontPtr = data->data();
std::unique_ptr<SkStreamAsset> fontData(new SkMemoryStream(std::move(data)));
- SkFontArguments params;
- params.setCollectionIndex(ttcIndex);
- params.setAxes(skiaAxes.data(), skiaAxes.size());
+ SkFontArguments args;
+ args.setCollectionIndex(ttcIndex);
+ args.setVariationDesignPosition({skVariation.data(), static_cast<int>(skVariation.size())});
sk_sp<SkFontMgr> fm(SkFontMgr::RefDefault());
- sk_sp<SkTypeface> face(fm->makeFromStream(std::move(fontData), params));
+ sk_sp<SkTypeface> face(fm->makeFromStream(std::move(fontData), args));
if (face == NULL) {
ALOGE("addFont failed to create font, invalid request");
builder->axes.clear();
diff --git a/libs/hwui/jni/Graphics.cpp b/libs/hwui/jni/Graphics.cpp
index f76ecb4c9c8a..ecbb55ec878d 100644
--- a/libs/hwui/jni/Graphics.cpp
+++ b/libs/hwui/jni/Graphics.cpp
@@ -470,7 +470,7 @@ SkRegion* GraphicsJNI::getNativeRegion(JNIEnv* env, jobject region)
///////////////////////////////////////////////////////////////////////////////////////////
-jobject GraphicsJNI::createBitmapRegionDecoder(JNIEnv* env, SkBitmapRegionDecoder* bitmap)
+jobject GraphicsJNI::createBitmapRegionDecoder(JNIEnv* env, skia::BitmapRegionDecoder* bitmap)
{
ALOG_ASSERT(bitmap != NULL);
diff --git a/libs/hwui/jni/GraphicsJNI.h b/libs/hwui/jni/GraphicsJNI.h
index b58a740a4c27..79ab617411e3 100644
--- a/libs/hwui/jni/GraphicsJNI.h
+++ b/libs/hwui/jni/GraphicsJNI.h
@@ -4,8 +4,8 @@
#include <cutils/compiler.h>
#include "Bitmap.h"
+#include "BRDAllocator.h"
#include "SkBitmap.h"
-#include "SkBRDAllocator.h"
#include "SkCodec.h"
#include "SkPixelRef.h"
#include "SkMallocPixelRef.h"
@@ -17,10 +17,12 @@
#include "graphics_jni_helpers.h"
-class SkBitmapRegionDecoder;
class SkCanvas;
namespace android {
+namespace skia {
+ class BitmapRegionDecoder;
+}
class Paint;
struct Typeface;
}
@@ -103,7 +105,8 @@ public:
static jobject createRegion(JNIEnv* env, SkRegion* region);
- static jobject createBitmapRegionDecoder(JNIEnv* env, SkBitmapRegionDecoder* bitmap);
+ static jobject createBitmapRegionDecoder(JNIEnv* env,
+ android::skia::BitmapRegionDecoder* bitmap);
/**
* Given a bitmap we natively allocate a memory block to store the contents
@@ -154,7 +157,7 @@ private:
static JavaVM* mJavaVM;
};
-class HeapAllocator : public SkBRDAllocator {
+class HeapAllocator : public android::skia::BRDAllocator {
public:
HeapAllocator() { };
~HeapAllocator() { };
@@ -181,7 +184,7 @@ private:
* the decoded output to fit in the recycled bitmap if necessary.
* This allocator implements that behavior.
*
- * Skia's SkBitmapRegionDecoder expects the memory that
+ * Skia's BitmapRegionDecoder expects the memory that
* is allocated to be large enough to decode the entire region
* that is requested. It will decode directly into the memory
* that is provided.
@@ -200,7 +203,7 @@ private:
* reuse it again, given that it still may be in use from our
* first allocation.
*/
-class RecyclingClippingPixelAllocator : public SkBRDAllocator {
+class RecyclingClippingPixelAllocator : public android::skia::BRDAllocator {
public:
RecyclingClippingPixelAllocator(android::Bitmap* recycledBitmap,
diff --git a/libs/hwui/jni/ImageDecoder.cpp b/libs/hwui/jni/ImageDecoder.cpp
index 41d939bd6373..1f4fd230e55e 100644
--- a/libs/hwui/jni/ImageDecoder.cpp
+++ b/libs/hwui/jni/ImageDecoder.cpp
@@ -27,9 +27,9 @@
#include <hwui/ImageDecoder.h>
#include <HardwareBitmapUploader.h>
+#include <FrontBufferedStream.h>
#include <SkAndroidCodec.h>
#include <SkEncodedImageFormat.h>
-#include <SkFrontBufferedStream.h>
#include <SkStream.h>
#include <androidfw/Asset.h>
@@ -187,8 +187,7 @@ static jobject ImageDecoder_nCreateInputStream(JNIEnv* env, jobject /*clazz*/,
}
std::unique_ptr<SkStream> bufferedStream(
- SkFrontBufferedStream::Make(std::move(stream),
- SkCodec::MinBufferedBytesNeeded()));
+ skia::FrontBufferedStream::Make(std::move(stream), SkCodec::MinBufferedBytesNeeded()));
return native_create(env, std::move(bufferedStream), source, preferAnimation);
}
diff --git a/libs/hwui/jni/Movie.cpp b/libs/hwui/jni/Movie.cpp
index ede0ca8cda5b..bb8c99a73edf 100644
--- a/libs/hwui/jni/Movie.cpp
+++ b/libs/hwui/jni/Movie.cpp
@@ -1,7 +1,7 @@
#include "CreateJavaOutputStreamAdaptor.h"
+#include "FrontBufferedStream.h"
#include "GraphicsJNI.h"
#include <nativehelper/ScopedLocalRef.h>
-#include "SkFrontBufferedStream.h"
#include "Movie.h"
#include "SkStream.h"
#include "SkUtils.h"
@@ -100,10 +100,8 @@ static jobject movie_decodeStream(JNIEnv* env, jobject clazz, jobject istream) {
// Need to buffer enough input to be able to rewind as much as might be read by a decoder
// trying to determine the stream's format. The only decoder for movies is GIF, which
// will only read 6.
- // FIXME: Get this number from SkImageDecoder
- // bufferedStream takes ownership of strm
- std::unique_ptr<SkStreamRewindable> bufferedStream(SkFrontBufferedStream::Make(
- std::unique_ptr<SkStream>(strm), 6));
+ std::unique_ptr<SkStreamRewindable> bufferedStream(
+ android::skia::FrontBufferedStream::Make(std::unique_ptr<SkStream>(strm), 6));
SkASSERT(bufferedStream.get() != NULL);
Movie* moov = Movie::DecodeStream(bufferedStream.get());
diff --git a/libs/hwui/jni/Shader.cpp b/libs/hwui/jni/Shader.cpp
index 0f6837640524..e76aace601be 100644
--- a/libs/hwui/jni/Shader.cpp
+++ b/libs/hwui/jni/Shader.cpp
@@ -228,9 +228,12 @@ static jlong RuntimeShader_create(JNIEnv* env, jobject, jlong shaderFactory, jlo
static jlong RuntimeShader_createShaderFactory(JNIEnv* env, jobject, jstring sksl) {
ScopedUtfChars strSksl(env, sksl);
- sk_sp<SkRuntimeEffect> effect = std::get<0>(SkRuntimeEffect::Make(SkString(strSksl.c_str())));
- ThrowIAE_IfNull(env, effect);
-
+ auto result = SkRuntimeEffect::Make(SkString(strSksl.c_str()));
+ sk_sp<SkRuntimeEffect> effect = std::get<0>(result);
+ if (!effect) {
+ const auto& err = std::get<1>(result);
+ doThrowIAE(env, err.c_str());
+ }
return reinterpret_cast<jlong>(effect.release());
}
diff --git a/libs/hwui/jni/Utils.cpp b/libs/hwui/jni/Utils.cpp
index 34fd6687d52c..ac2f5b77d23a 100644
--- a/libs/hwui/jni/Utils.cpp
+++ b/libs/hwui/jni/Utils.cpp
@@ -114,7 +114,7 @@ size_t AssetStreamAdaptor::read(void* buffer, size_t size) {
return amount;
}
-SkMemoryStream* android::CopyAssetToStream(Asset* asset) {
+sk_sp<SkData> android::CopyAssetToData(Asset* asset) {
if (NULL == asset) {
return NULL;
}
@@ -138,7 +138,7 @@ SkMemoryStream* android::CopyAssetToStream(Asset* asset) {
return NULL;
}
- return new SkMemoryStream(std::move(data));
+ return data;
}
jobject android::nullObjectReturn(const char msg[]) {
diff --git a/libs/hwui/jni/Utils.h b/libs/hwui/jni/Utils.h
index f628cc3c85ed..6cdf44d85a5a 100644
--- a/libs/hwui/jni/Utils.h
+++ b/libs/hwui/jni/Utils.h
@@ -46,12 +46,11 @@ private:
};
/**
- * Make a deep copy of the asset, and return it as a stream, or NULL if there
+ * Make a deep copy of the asset, and return it as an SkData, or NULL if there
* was an error.
- * FIXME: If we could "ref/reopen" the asset, we may not need to copy it here.
*/
-SkMemoryStream* CopyAssetToStream(Asset*);
+sk_sp<SkData> CopyAssetToData(Asset*);
/** Restore the file descriptor's offset in our destructor
*/
diff --git a/libs/hwui/jni/android_graphics_DisplayListCanvas.cpp b/libs/hwui/jni/android_graphics_DisplayListCanvas.cpp
index 54822f1f07e2..7c1422de0984 100644
--- a/libs/hwui/jni/android_graphics_DisplayListCanvas.cpp
+++ b/libs/hwui/jni/android_graphics_DisplayListCanvas.cpp
@@ -67,39 +67,7 @@ private:
JavaVM* mVm;
jobject mRunnable;
};
-
-class GlFunctorReleasedCallbackBridge : public GlFunctorLifecycleListener {
-public:
- GlFunctorReleasedCallbackBridge(JNIEnv* env, jobject javaCallback) {
- mLooper = Looper::getForThread();
- mMessage = new InvokeRunnableMessage(env, javaCallback);
- }
-
- virtual void onGlFunctorReleased(Functor* functor) override {
- mLooper->sendMessage(mMessage, 0);
- }
-
-private:
- sp<Looper> mLooper;
- sp<InvokeRunnableMessage> mMessage;
-};
-#endif
-
-// ---------------- @FastNative -----------------------------
-
-static void android_view_DisplayListCanvas_callDrawGLFunction(JNIEnv* env, jobject clazz,
- jlong canvasPtr, jlong functorPtr, jobject releasedCallback) {
-#ifdef __ANDROID__ // Layoutlib does not support GL
- Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
- Functor* functor = reinterpret_cast<Functor*>(functorPtr);
- sp<GlFunctorReleasedCallbackBridge> bridge;
- if (releasedCallback) {
- bridge = new GlFunctorReleasedCallbackBridge(env, releasedCallback);
- }
- canvas->callDrawGLFunction(functor, bridge.get());
#endif
-}
-
// ---------------- @CriticalNative -------------------------
@@ -124,10 +92,10 @@ static jint android_view_DisplayListCanvas_getMaxTextureSize(CRITICAL_JNI_PARAMS
#endif
}
-static void android_view_DisplayListCanvas_insertReorderBarrier(CRITICAL_JNI_PARAMS_COMMA jlong canvasPtr,
+static void android_view_DisplayListCanvas_enableZ(CRITICAL_JNI_PARAMS_COMMA jlong canvasPtr,
jboolean reorderEnable) {
Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
- canvas->insertReorderBarrier(reorderEnable);
+ canvas->enableZ(reorderEnable);
}
static jlong android_view_DisplayListCanvas_finishRecording(CRITICAL_JNI_PARAMS_COMMA jlong canvasPtr) {
@@ -183,18 +151,12 @@ static void android_view_DisplayListCanvas_drawWebViewFunctor(CRITICAL_JNI_PARAM
const char* const kClassPathName = "android/graphics/RecordingCanvas";
static JNINativeMethod gMethods[] = {
-
- // ------------ @FastNative ------------------
-
- { "nCallDrawGLFunction", "(JJLjava/lang/Runnable;)V",
- (void*) android_view_DisplayListCanvas_callDrawGLFunction },
-
// ------------ @CriticalNative --------------
{ "nCreateDisplayListCanvas", "(JII)J", (void*) android_view_DisplayListCanvas_createDisplayListCanvas },
{ "nResetDisplayListCanvas", "(JJII)V", (void*) android_view_DisplayListCanvas_resetDisplayListCanvas },
{ "nGetMaximumTextureWidth", "()I", (void*) android_view_DisplayListCanvas_getMaxTextureSize },
{ "nGetMaximumTextureHeight", "()I", (void*) android_view_DisplayListCanvas_getMaxTextureSize },
- { "nInsertReorderBarrier", "(JZ)V", (void*) android_view_DisplayListCanvas_insertReorderBarrier },
+ { "nEnableZ", "(JZ)V", (void*) android_view_DisplayListCanvas_enableZ },
{ "nFinishRecording", "(J)J", (void*) android_view_DisplayListCanvas_finishRecording },
{ "nDrawRenderNode", "(JJ)V", (void*) android_view_DisplayListCanvas_drawRenderNode },
{ "nDrawTextureLayer", "(JJ)V", (void*) android_view_DisplayListCanvas_drawTextureLayer },
diff --git a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
index 9815e85db880..fc594da19708 100644
--- a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
+++ b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
@@ -143,11 +143,10 @@ static jlong android_view_ThreadedRenderer_createRootRenderNode(JNIEnv* env, job
}
static jlong android_view_ThreadedRenderer_createProxy(JNIEnv* env, jobject clazz,
- jboolean translucent, jboolean isWideGamut, jlong rootRenderNodePtr) {
+ jboolean translucent, jlong rootRenderNodePtr) {
RootRenderNode* rootRenderNode = reinterpret_cast<RootRenderNode*>(rootRenderNodePtr);
ContextFactoryImpl factory(rootRenderNode);
RenderProxy* proxy = new RenderProxy(translucent, rootRenderNode, &factory);
- proxy->setWideGamut(isWideGamut);
return (jlong) proxy;
}
@@ -218,10 +217,15 @@ static void android_view_ThreadedRenderer_setOpaque(JNIEnv* env, jobject clazz,
proxy->setOpaque(opaque);
}
-static void android_view_ThreadedRenderer_setWideGamut(JNIEnv* env, jobject clazz,
- jlong proxyPtr, jboolean wideGamut) {
+static void android_view_ThreadedRenderer_setColorMode(JNIEnv* env, jobject clazz,
+ jlong proxyPtr, jint colorMode) {
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
- proxy->setWideGamut(wideGamut);
+ proxy->setColorMode(static_cast<ColorMode>(colorMode));
+}
+
+static void android_view_ThreadedRenderer_setSdrWhitePoint(JNIEnv* env, jobject clazz,
+ jlong proxyPtr, jfloat sdrWhitePoint) {
+ Properties::defaultSdrWhitePoint = sdrWhitePoint;
}
static int android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject clazz,
@@ -256,12 +260,6 @@ static void android_view_ThreadedRenderer_registerVectorDrawableAnimator(JNIEnv*
rootRenderNode->addVectorDrawableAnimator(animator);
}
-static void android_view_ThreadedRenderer_invokeFunctor(JNIEnv* env, jobject clazz,
- jlong functorPtr, jboolean waitForCompletion) {
- Functor* functor = reinterpret_cast<Functor*>(functorPtr);
- RenderProxy::invokeFunctor(functor, waitForCompletion);
-}
-
static jlong android_view_ThreadedRenderer_createTextureLayer(JNIEnv* env, jobject clazz,
jlong proxyPtr) {
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
@@ -593,6 +591,28 @@ static void android_view_ThreadedRenderer_preload(JNIEnv*, jclass) {
RenderProxy::preload();
}
+// Plumbs the display density down to DeviceInfo.
+static void android_view_ThreadedRenderer_setDisplayDensityDpi(JNIEnv*, jclass, jint densityDpi) {
+ // Convert from dpi to density-independent pixels.
+ const float density = densityDpi / 160.0;
+ DeviceInfo::setDensity(density);
+}
+
+static void android_view_ThreadedRenderer_initDisplayInfo(JNIEnv*, jclass, jint physicalWidth,
+ jint physicalHeight, jfloat refreshRate,
+ jfloat maxRefreshRate,
+ jint wideColorDataspace,
+ jlong appVsyncOffsetNanos,
+ jlong presentationDeadlineNanos) {
+ DeviceInfo::setWidth(physicalWidth);
+ DeviceInfo::setHeight(physicalHeight);
+ DeviceInfo::setRefreshRate(refreshRate);
+ DeviceInfo::setMaxRefreshRate(maxRefreshRate);
+ DeviceInfo::setWideColorDataspace(static_cast<ADataSpace>(wideColorDataspace));
+ DeviceInfo::setAppVsyncOffsetNanos(appVsyncOffsetNanos);
+ DeviceInfo::setPresentationDeadlineNanos(presentationDeadlineNanos);
+}
+
// ----------------------------------------------------------------------------
// HardwareRendererObserver
// ----------------------------------------------------------------------------
@@ -637,67 +657,83 @@ static void android_view_ThreadedRenderer_setupShadersDiskCache(JNIEnv* env, job
const char* const kClassPathName = "android/graphics/HardwareRenderer";
static const JNINativeMethod gMethods[] = {
- { "nRotateProcessStatsBuffer", "()V", (void*) android_view_ThreadedRenderer_rotateProcessStatsBuffer },
- { "nSetProcessStatsBuffer", "(I)V", (void*) android_view_ThreadedRenderer_setProcessStatsBuffer },
- { "nGetRenderThreadTid", "(J)I", (void*) android_view_ThreadedRenderer_getRenderThreadTid },
- { "nCreateRootRenderNode", "()J", (void*) android_view_ThreadedRenderer_createRootRenderNode },
- { "nCreateProxy", "(ZZJ)J", (void*) android_view_ThreadedRenderer_createProxy },
- { "nDeleteProxy", "(J)V", (void*) android_view_ThreadedRenderer_deleteProxy },
- { "nLoadSystemProperties", "(J)Z", (void*) android_view_ThreadedRenderer_loadSystemProperties },
- { "nSetName", "(JLjava/lang/String;)V", (void*) android_view_ThreadedRenderer_setName },
- { "nSetSurface", "(JLandroid/view/Surface;Z)V", (void*) android_view_ThreadedRenderer_setSurface },
- { "nPause", "(J)Z", (void*) android_view_ThreadedRenderer_pause },
- { "nSetStopped", "(JZ)V", (void*) android_view_ThreadedRenderer_setStopped },
- { "nSetLightAlpha", "(JFF)V", (void*) android_view_ThreadedRenderer_setLightAlpha },
- { "nSetLightGeometry", "(JFFFF)V", (void*) android_view_ThreadedRenderer_setLightGeometry },
- { "nSetOpaque", "(JZ)V", (void*) android_view_ThreadedRenderer_setOpaque },
- { "nSetWideGamut", "(JZ)V", (void*) android_view_ThreadedRenderer_setWideGamut },
- { "nSyncAndDrawFrame", "(J[JI)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame },
- { "nDestroy", "(JJ)V", (void*) android_view_ThreadedRenderer_destroy },
- { "nRegisterAnimatingRenderNode", "(JJ)V", (void*) android_view_ThreadedRenderer_registerAnimatingRenderNode },
- { "nRegisterVectorDrawableAnimator", "(JJ)V", (void*) android_view_ThreadedRenderer_registerVectorDrawableAnimator },
- { "nInvokeFunctor", "(JZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor },
- { "nCreateTextureLayer", "(J)J", (void*) android_view_ThreadedRenderer_createTextureLayer },
- { "nBuildLayer", "(JJ)V", (void*) android_view_ThreadedRenderer_buildLayer },
- { "nCopyLayerInto", "(JJJ)Z", (void*) android_view_ThreadedRenderer_copyLayerInto },
- { "nPushLayerUpdate", "(JJ)V", (void*) android_view_ThreadedRenderer_pushLayerUpdate },
- { "nCancelLayerUpdate", "(JJ)V", (void*) android_view_ThreadedRenderer_cancelLayerUpdate },
- { "nDetachSurfaceTexture", "(JJ)V", (void*) android_view_ThreadedRenderer_detachSurfaceTexture },
- { "nDestroyHardwareResources", "(J)V", (void*) android_view_ThreadedRenderer_destroyHardwareResources },
- { "nTrimMemory", "(I)V", (void*) android_view_ThreadedRenderer_trimMemory },
- { "nOverrideProperty", "(Ljava/lang/String;Ljava/lang/String;)V", (void*) android_view_ThreadedRenderer_overrideProperty },
- { "nFence", "(J)V", (void*) android_view_ThreadedRenderer_fence },
- { "nStopDrawing", "(J)V", (void*) android_view_ThreadedRenderer_stopDrawing },
- { "nNotifyFramePending", "(J)V", (void*) android_view_ThreadedRenderer_notifyFramePending },
- { "nDumpProfileInfo", "(JLjava/io/FileDescriptor;I)V", (void*) android_view_ThreadedRenderer_dumpProfileInfo },
- { "setupShadersDiskCache", "(Ljava/lang/String;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},
- { "nSetContentDrawBounds", "(JIIII)V", (void*)android_view_ThreadedRenderer_setContentDrawBounds},
- { "nSetPictureCaptureCallback", "(JLandroid/graphics/HardwareRenderer$PictureCapturedCallback;)V",
- (void*) android_view_ThreadedRenderer_setPictureCapturedCallbackJNI },
- { "nSetFrameCallback", "(JLandroid/graphics/HardwareRenderer$FrameDrawingCallback;)V",
- (void*)android_view_ThreadedRenderer_setFrameCallback},
- { "nSetFrameCompleteCallback", "(JLandroid/graphics/HardwareRenderer$FrameCompleteCallback;)V",
- (void*)android_view_ThreadedRenderer_setFrameCompleteCallback },
- { "nAddObserver", "(JJ)V", (void*)android_view_ThreadedRenderer_addObserver },
- { "nRemoveObserver", "(JJ)V", (void*)android_view_ThreadedRenderer_removeObserver },
- { "nCopySurfaceInto", "(Landroid/view/Surface;IIIIJ)I",
- (void*)android_view_ThreadedRenderer_copySurfaceInto },
- { "nCreateHardwareBitmap", "(JII)Landroid/graphics/Bitmap;",
- (void*)android_view_ThreadedRenderer_createHardwareBitmapFromRenderNode },
- { "disableVsync", "()V", (void*)android_view_ThreadedRenderer_disableVsync },
- { "nSetHighContrastText", "(Z)V", (void*)android_view_ThreadedRenderer_setHighContrastText },
- { "nHackySetRTAnimationsEnabled", "(Z)V",
- (void*)android_view_ThreadedRenderer_hackySetRTAnimationsEnabled },
- { "nSetDebuggingEnabled", "(Z)V", (void*)android_view_ThreadedRenderer_setDebuggingEnabled },
- { "nSetIsolatedProcess", "(Z)V", (void*)android_view_ThreadedRenderer_setIsolatedProcess },
- { "nSetContextPriority", "(I)V", (void*)android_view_ThreadedRenderer_setContextPriority },
- { "nAllocateBuffers", "(J)V", (void*)android_view_ThreadedRenderer_allocateBuffers },
- { "nSetForceDark", "(JZ)V", (void*)android_view_ThreadedRenderer_setForceDark },
- { "preload", "()V", (void*)android_view_ThreadedRenderer_preload },
+ {"nRotateProcessStatsBuffer", "()V",
+ (void*)android_view_ThreadedRenderer_rotateProcessStatsBuffer},
+ {"nSetProcessStatsBuffer", "(I)V",
+ (void*)android_view_ThreadedRenderer_setProcessStatsBuffer},
+ {"nGetRenderThreadTid", "(J)I", (void*)android_view_ThreadedRenderer_getRenderThreadTid},
+ {"nCreateRootRenderNode", "()J", (void*)android_view_ThreadedRenderer_createRootRenderNode},
+ {"nCreateProxy", "(ZJ)J", (void*)android_view_ThreadedRenderer_createProxy},
+ {"nDeleteProxy", "(J)V", (void*)android_view_ThreadedRenderer_deleteProxy},
+ {"nLoadSystemProperties", "(J)Z",
+ (void*)android_view_ThreadedRenderer_loadSystemProperties},
+ {"nSetName", "(JLjava/lang/String;)V", (void*)android_view_ThreadedRenderer_setName},
+ {"nSetSurface", "(JLandroid/view/Surface;Z)V",
+ (void*)android_view_ThreadedRenderer_setSurface},
+ {"nPause", "(J)Z", (void*)android_view_ThreadedRenderer_pause},
+ {"nSetStopped", "(JZ)V", (void*)android_view_ThreadedRenderer_setStopped},
+ {"nSetLightAlpha", "(JFF)V", (void*)android_view_ThreadedRenderer_setLightAlpha},
+ {"nSetLightGeometry", "(JFFFF)V", (void*)android_view_ThreadedRenderer_setLightGeometry},
+ {"nSetOpaque", "(JZ)V", (void*)android_view_ThreadedRenderer_setOpaque},
+ {"nSetColorMode", "(JI)V", (void*)android_view_ThreadedRenderer_setColorMode},
+ {"nSetSdrWhitePoint", "(JF)V", (void*)android_view_ThreadedRenderer_setSdrWhitePoint},
+ {"nSyncAndDrawFrame", "(J[JI)I", (void*)android_view_ThreadedRenderer_syncAndDrawFrame},
+ {"nDestroy", "(JJ)V", (void*)android_view_ThreadedRenderer_destroy},
+ {"nRegisterAnimatingRenderNode", "(JJ)V",
+ (void*)android_view_ThreadedRenderer_registerAnimatingRenderNode},
+ {"nRegisterVectorDrawableAnimator", "(JJ)V",
+ (void*)android_view_ThreadedRenderer_registerVectorDrawableAnimator},
+ {"nCreateTextureLayer", "(J)J", (void*)android_view_ThreadedRenderer_createTextureLayer},
+ {"nBuildLayer", "(JJ)V", (void*)android_view_ThreadedRenderer_buildLayer},
+ {"nCopyLayerInto", "(JJJ)Z", (void*)android_view_ThreadedRenderer_copyLayerInto},
+ {"nPushLayerUpdate", "(JJ)V", (void*)android_view_ThreadedRenderer_pushLayerUpdate},
+ {"nCancelLayerUpdate", "(JJ)V", (void*)android_view_ThreadedRenderer_cancelLayerUpdate},
+ {"nDetachSurfaceTexture", "(JJ)V",
+ (void*)android_view_ThreadedRenderer_detachSurfaceTexture},
+ {"nDestroyHardwareResources", "(J)V",
+ (void*)android_view_ThreadedRenderer_destroyHardwareResources},
+ {"nTrimMemory", "(I)V", (void*)android_view_ThreadedRenderer_trimMemory},
+ {"nOverrideProperty", "(Ljava/lang/String;Ljava/lang/String;)V",
+ (void*)android_view_ThreadedRenderer_overrideProperty},
+ {"nFence", "(J)V", (void*)android_view_ThreadedRenderer_fence},
+ {"nStopDrawing", "(J)V", (void*)android_view_ThreadedRenderer_stopDrawing},
+ {"nNotifyFramePending", "(J)V", (void*)android_view_ThreadedRenderer_notifyFramePending},
+ {"nDumpProfileInfo", "(JLjava/io/FileDescriptor;I)V",
+ (void*)android_view_ThreadedRenderer_dumpProfileInfo},
+ {"setupShadersDiskCache", "(Ljava/lang/String;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},
+ {"nSetContentDrawBounds", "(JIIII)V",
+ (void*)android_view_ThreadedRenderer_setContentDrawBounds},
+ {"nSetPictureCaptureCallback",
+ "(JLandroid/graphics/HardwareRenderer$PictureCapturedCallback;)V",
+ (void*)android_view_ThreadedRenderer_setPictureCapturedCallbackJNI},
+ {"nSetFrameCallback", "(JLandroid/graphics/HardwareRenderer$FrameDrawingCallback;)V",
+ (void*)android_view_ThreadedRenderer_setFrameCallback},
+ {"nSetFrameCompleteCallback",
+ "(JLandroid/graphics/HardwareRenderer$FrameCompleteCallback;)V",
+ (void*)android_view_ThreadedRenderer_setFrameCompleteCallback},
+ {"nAddObserver", "(JJ)V", (void*)android_view_ThreadedRenderer_addObserver},
+ {"nRemoveObserver", "(JJ)V", (void*)android_view_ThreadedRenderer_removeObserver},
+ {"nCopySurfaceInto", "(Landroid/view/Surface;IIIIJ)I",
+ (void*)android_view_ThreadedRenderer_copySurfaceInto},
+ {"nCreateHardwareBitmap", "(JII)Landroid/graphics/Bitmap;",
+ (void*)android_view_ThreadedRenderer_createHardwareBitmapFromRenderNode},
+ {"disableVsync", "()V", (void*)android_view_ThreadedRenderer_disableVsync},
+ {"nSetHighContrastText", "(Z)V", (void*)android_view_ThreadedRenderer_setHighContrastText},
+ {"nHackySetRTAnimationsEnabled", "(Z)V",
+ (void*)android_view_ThreadedRenderer_hackySetRTAnimationsEnabled},
+ {"nSetDebuggingEnabled", "(Z)V", (void*)android_view_ThreadedRenderer_setDebuggingEnabled},
+ {"nSetIsolatedProcess", "(Z)V", (void*)android_view_ThreadedRenderer_setIsolatedProcess},
+ {"nSetContextPriority", "(I)V", (void*)android_view_ThreadedRenderer_setContextPriority},
+ {"nAllocateBuffers", "(J)V", (void*)android_view_ThreadedRenderer_allocateBuffers},
+ {"nSetForceDark", "(JZ)V", (void*)android_view_ThreadedRenderer_setForceDark},
+ {"nSetDisplayDensityDpi", "(I)V",
+ (void*)android_view_ThreadedRenderer_setDisplayDensityDpi},
+ {"nInitDisplayInfo", "(IIFFIJJ)V", (void*)android_view_ThreadedRenderer_initDisplayInfo},
+ {"preload", "()V", (void*)android_view_ThreadedRenderer_preload},
};
static JavaVM* mJvm = nullptr;
diff --git a/libs/hwui/jni/android_graphics_TextureLayer.cpp b/libs/hwui/jni/android_graphics_TextureLayer.cpp
index bd20269d3751..4dbb24ce4347 100644
--- a/libs/hwui/jni/android_graphics_TextureLayer.cpp
+++ b/libs/hwui/jni/android_graphics_TextureLayer.cpp
@@ -67,7 +67,7 @@ static void TextureLayer_updateSurfaceTexture(JNIEnv* env, jobject clazz,
// JNI Glue
// ----------------------------------------------------------------------------
-const char* const kClassPathName = "android/view/TextureLayer";
+const char* const kClassPathName = "android/graphics/TextureLayer";
static const JNINativeMethod gMethods[] = {
{ "nPrepare", "(JIIZ)Z", (void*) TextureLayer_prepare },
@@ -78,7 +78,7 @@ static const JNINativeMethod gMethods[] = {
{ "nUpdateSurfaceTexture", "(J)V", (void*) TextureLayer_updateSurfaceTexture },
};
-int register_android_view_TextureLayer(JNIEnv* env) {
+int register_android_graphics_TextureLayer(JNIEnv* env) {
return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
}
diff --git a/libs/hwui/jni/fonts/Font.cpp b/libs/hwui/jni/fonts/Font.cpp
index 5714cd1d0390..996cdceed8a7 100644
--- a/libs/hwui/jni/fonts/Font.cpp
+++ b/libs/hwui/jni/fonts/Font.cpp
@@ -93,19 +93,19 @@ static jlong Font_Builder_build(JNIEnv* env, jobject clazz, jlong builderPtr, jo
sk_sp<SkData> data(SkData::MakeWithProc(fontPtr, fontSize,
release_global_ref, reinterpret_cast<void*>(fontRef)));
- FatVector<SkFontArguments::Axis, 2> skiaAxes;
+ FatVector<SkFontArguments::VariationPosition::Coordinate, 2> skVariation;
for (const auto& axis : builder->axes) {
- skiaAxes.emplace_back(SkFontArguments::Axis{axis.axisTag, axis.value});
+ skVariation.push_back({axis.axisTag, axis.value});
}
std::unique_ptr<SkStreamAsset> fontData(new SkMemoryStream(std::move(data)));
- SkFontArguments params;
- params.setCollectionIndex(ttcIndex);
- params.setAxes(skiaAxes.data(), skiaAxes.size());
+ SkFontArguments args;
+ args.setCollectionIndex(ttcIndex);
+ args.setVariationDesignPosition({skVariation.data(), static_cast<int>(skVariation.size())});
sk_sp<SkFontMgr> fm(SkFontMgr::RefDefault());
- sk_sp<SkTypeface> face(fm->makeFromStream(std::move(fontData), params));
+ sk_sp<SkTypeface> face(fm->makeFromStream(std::move(fontData), args));
if (face == nullptr) {
jniThrowException(env, "java/lang/IllegalArgumentException",
"Failed to create internal object. maybe invalid font data.");
diff --git a/libs/hwui/libhwui.map.txt b/libs/hwui/libhwui.map.txt
new file mode 100644
index 000000000000..73de0d12a60b
--- /dev/null
+++ b/libs/hwui/libhwui.map.txt
@@ -0,0 +1,70 @@
+LIBHWUI {
+ global:
+ /* listing of all C APIs to be exposed by libhwui to consumers outside of the module */
+ ABitmap_getInfoFromJava;
+ ABitmap_acquireBitmapFromJava;
+ ABitmap_copy;
+ ABitmap_acquireRef;
+ ABitmap_releaseRef;
+ ABitmap_getInfo;
+ ABitmap_getDataSpace;
+ ABitmap_getPixels;
+ ABitmap_notifyPixelsChanged;
+ ABitmapConfig_getFormatFromConfig;
+ ABitmapConfig_getConfigFromFormat;
+ ABitmap_compress;
+ ABitmap_getHardwareBuffer;
+ ACanvas_isSupportedPixelFormat;
+ ACanvas_getNativeHandleFromJava;
+ ACanvas_createCanvas;
+ ACanvas_destroyCanvas;
+ ACanvas_setBuffer;
+ ACanvas_clipRect;
+ ACanvas_clipOutRect;
+ ACanvas_drawRect;
+ ACanvas_drawBitmap;
+ init_android_graphics;
+ register_android_graphics_classes;
+ register_android_graphics_GraphicsStatsService;
+ zygote_preload_graphics;
+ AMatrix_getContents;
+ APaint_createPaint;
+ APaint_destroyPaint;
+ APaint_setBlendMode;
+ ARegionIterator_acquireIterator;
+ ARegionIterator_releaseIterator;
+ ARegionIterator_isComplex;
+ ARegionIterator_isDone;
+ ARegionIterator_next;
+ ARegionIterator_getRect;
+ ARegionIterator_getTotalBounds;
+ ARenderThread_dumpGraphicsMemory;
+ local:
+ *;
+};
+
+LIBHWUI_PLATFORM {
+ global:
+ extern "C++" {
+ /* required by libwebviewchromium_plat_support */
+ android::uirenderer::ColorSpaceToADataSpace*;
+ android::uirenderer::WebViewFunctor_*;
+ GraphicsJNI::getNativeCanvas*;
+ SkCanvasStateUtils::ReleaseCanvasState*;
+ SkColorSpace::toXYZD50*;
+ SkColorSpace::transferFn*;
+ /* required by libjnigraphics */
+ android::ImageDecoder::*;
+ android::uirenderer::DataSpaceToColorSpace*;
+ android::uirenderer::ColorSpaceToADataSpace*;
+ getMimeType*;
+ SkAndroidCodec::*;
+ SkCodec::MakeFromStream*;
+ SkColorInfo::*;
+ SkFILEStream::SkFILEStream*;
+ SkImageInfo::*;
+ SkMemoryStream::SkMemoryStream*;
+ };
+ local:
+ *;
+};
diff --git a/libs/hwui/pipeline/skia/FunctorDrawable.h b/libs/hwui/pipeline/skia/FunctorDrawable.h
index cf2f93b95e71..988a896b6267 100644
--- a/libs/hwui/pipeline/skia/FunctorDrawable.h
+++ b/libs/hwui/pipeline/skia/FunctorDrawable.h
@@ -16,8 +16,6 @@
#pragma once
-#include "GlFunctorLifecycleListener.h"
-
#include <SkCanvas.h>
#include <SkDrawable.h>
@@ -36,44 +34,21 @@ namespace skiapipeline {
*/
class FunctorDrawable : public SkDrawable {
public:
- FunctorDrawable(Functor* functor, GlFunctorLifecycleListener* listener, SkCanvas* canvas)
- : mBounds(canvas->getLocalClipBounds())
- , mAnyFunctor(std::in_place_type<LegacyFunctor>, functor, listener) {}
-
FunctorDrawable(int functor, SkCanvas* canvas)
: mBounds(canvas->getLocalClipBounds())
- , mAnyFunctor(std::in_place_type<NewFunctor>, functor) {}
+ , mWebViewHandle(WebViewFunctorManager::instance().handleFor(functor)) {}
virtual ~FunctorDrawable() {}
virtual void syncFunctor(const WebViewSyncData& data) const {
- if (mAnyFunctor.index() == 0) {
- std::get<0>(mAnyFunctor).handle->sync(data);
- } else {
- (*(std::get<1>(mAnyFunctor).functor))(DrawGlInfo::kModeSync, nullptr);
- }
+ mWebViewHandle->sync(data);
}
protected:
virtual SkRect onGetBounds() override { return mBounds; }
const SkRect mBounds;
-
- struct LegacyFunctor {
- explicit LegacyFunctor(Functor* functor, GlFunctorLifecycleListener* listener)
- : functor(functor), listener(listener) {}
- Functor* functor;
- sp<GlFunctorLifecycleListener> listener;
- };
-
- struct NewFunctor {
- explicit NewFunctor(int functor) {
- handle = WebViewFunctorManager::instance().handleFor(functor);
- }
- sp<WebViewFunctor::Handle> handle;
- };
-
- std::variant<NewFunctor, LegacyFunctor> mAnyFunctor;
+ sp<WebViewFunctor::Handle> mWebViewHandle;
};
} // namespace skiapipeline
diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
index 8f67f97fb4bc..dd0fc695c246 100644
--- a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
@@ -15,10 +15,9 @@
*/
#include "GLFunctorDrawable.h"
-#include <GrContext.h>
+#include <GrDirectContext.h>
#include <private/hwui/DrawGlInfo.h>
#include "FunctorDrawable.h"
-#include "GlFunctorLifecycleListener.h"
#include "GrBackendSurface.h"
#include "GrRenderTarget.h"
#include "GrRenderTargetContext.h"
@@ -26,20 +25,12 @@
#include "SkAndroidFrameworkUtils.h"
#include "SkClipStack.h"
#include "SkRect.h"
-#include "include/private/SkM44.h"
+#include "SkM44.h"
namespace android {
namespace uirenderer {
namespace skiapipeline {
-GLFunctorDrawable::~GLFunctorDrawable() {
- if (auto lp = std::get_if<LegacyFunctor>(&mAnyFunctor)) {
- if (lp->listener) {
- lp->listener->onGlFunctorReleased(lp->functor);
- }
- }
-}
-
static void setScissor(int viewportHeight, const SkIRect& clip) {
SkASSERT(!clip.isEmpty());
// transform to Y-flipped GL space, and prevent negatives
@@ -85,7 +76,7 @@ void GLFunctorDrawable::onDraw(SkCanvas* canvas) {
SkIRect surfaceBounds = canvas->internal_private_getTopLayerBounds();
SkIRect clipBounds = canvas->getDeviceClipBounds();
- SkM44 mat4(canvas->experimental_getLocalToDevice());
+ SkM44 mat4(canvas->getLocalToDevice());
SkRegion clipRegion;
canvas->temporary_internal_getRgnClip(&clipRegion);
@@ -186,11 +177,7 @@ void GLFunctorDrawable::onDraw(SkCanvas* canvas) {
setScissor(info.height, clipRegion.getBounds());
}
- if (mAnyFunctor.index() == 0) {
- std::get<0>(mAnyFunctor).handle->drawGl(info);
- } else {
- (*(std::get<1>(mAnyFunctor).functor))(DrawGlInfo::kModeDraw, &info);
- }
+ mWebViewHandle->drawGl(info);
if (clearStencilAfterFunctor) {
// clear stencil buffer as it may be used by Skia
diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.h b/libs/hwui/pipeline/skia/GLFunctorDrawable.h
index 2ea4f67428bc..4092e8dfa3a5 100644
--- a/libs/hwui/pipeline/skia/GLFunctorDrawable.h
+++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.h
@@ -33,7 +33,7 @@ class GLFunctorDrawable : public FunctorDrawable {
public:
using FunctorDrawable::FunctorDrawable;
- virtual ~GLFunctorDrawable();
+ virtual ~GLFunctorDrawable() {}
protected:
void onDraw(SkCanvas* canvas) override;
diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp
index f839213e9007..f95f347cffaf 100644
--- a/libs/hwui/pipeline/skia/LayerDrawable.cpp
+++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp
@@ -29,7 +29,7 @@ namespace skiapipeline {
void LayerDrawable::onDraw(SkCanvas* canvas) {
Layer* layer = mLayerUpdater->backingLayer();
if (layer) {
- DrawLayer(canvas->getGrContext(), canvas, layer, nullptr, nullptr, true);
+ DrawLayer(canvas->recordingContext(), canvas, layer, nullptr, nullptr, true);
}
}
@@ -67,8 +67,12 @@ static bool shouldFilterRect(const SkMatrix& matrix, const SkRect& srcRect, cons
isIntegerAligned(dstDevRect.y()));
}
-bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer,
- const SkRect* srcRect, const SkRect* dstRect,
+// TODO: Context arg probably doesn't belong here – do debug check at callsite instead.
+bool LayerDrawable::DrawLayer(GrRecordingContext* context,
+ SkCanvas* canvas,
+ Layer* layer,
+ const SkRect* srcRect,
+ const SkRect* dstRect,
bool useLayerTransform) {
if (context == nullptr) {
SkDEBUGF(("Attempting to draw LayerDrawable into an unsupported surface"));
diff --git a/libs/hwui/pipeline/skia/LayerDrawable.h b/libs/hwui/pipeline/skia/LayerDrawable.h
index 7cd515ae9fcb..ffbb480023ac 100644
--- a/libs/hwui/pipeline/skia/LayerDrawable.h
+++ b/libs/hwui/pipeline/skia/LayerDrawable.h
@@ -32,8 +32,12 @@ class LayerDrawable : public SkDrawable {
public:
explicit LayerDrawable(DeferredLayerUpdater* layerUpdater) : mLayerUpdater(layerUpdater) {}
- static bool DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer, const SkRect* srcRect,
- const SkRect* dstRect, bool useLayerTransform);
+ static bool DrawLayer(GrRecordingContext* context,
+ SkCanvas* canvas,
+ Layer* layer,
+ const SkRect* srcRect,
+ const SkRect* dstRect,
+ bool useLayerTransform);
protected:
virtual SkRect onGetBounds() override {
diff --git a/libs/hwui/pipeline/skia/ShaderCache.h b/libs/hwui/pipeline/skia/ShaderCache.h
index 0898017d52a1..5b8e668a56f4 100644
--- a/libs/hwui/pipeline/skia/ShaderCache.h
+++ b/libs/hwui/pipeline/skia/ShaderCache.h
@@ -37,7 +37,7 @@ public:
* "get" returns a pointer to the singleton ShaderCache object. This
* singleton object will never be destroyed.
*/
- ANDROID_API static ShaderCache& get();
+ static ShaderCache& get();
/**
* initShaderDiskCache" loads the serialized cache contents from disk,
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index 24a6228242a5..389fe7eed7c7 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -87,6 +87,8 @@ bool SkiaOpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty, con
// Note: The default preference of pixel format is RGBA_8888, when other
// pixel format is available, we should branch out and do more check.
fboInfo.fFormat = GL_RGBA8;
+ } else if (colorType == kRGBA_1010102_SkColorType) {
+ fboInfo.fFormat = GL_RGB10_A2;
} else {
LOG_ALWAYS_FATAL("Unsupported color type.");
}
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 5088494d6a07..6dd36981e8aa 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -35,6 +35,7 @@
#include "VectorDrawable.h"
#include "thread/CommonPool.h"
#include "tools/SkSharingProc.h"
+#include "utils/Color.h"
#include "utils/String8.h"
#include "utils/TraceUtils.h"
@@ -145,7 +146,7 @@ void SkiaPipeline::renderLayersImpl(const LayerUpdateQueue& layers, bool opaque)
if (cachedContext.get() != currentContext) {
if (cachedContext.get()) {
ATRACE_NAME("flush layers (context changed)");
- cachedContext->flush();
+ cachedContext->flushAndSubmit();
}
cachedContext.reset(SkSafeRef(currentContext));
}
@@ -153,7 +154,7 @@ void SkiaPipeline::renderLayersImpl(const LayerUpdateQueue& layers, bool opaque)
if (cachedContext.get()) {
ATRACE_NAME("flush layers");
- cachedContext->flush();
+ cachedContext->flushAndSubmit();
}
}
@@ -450,7 +451,7 @@ void SkiaPipeline::renderFrame(const LayerUpdateQueue& layers, const SkRect& cli
}
ATRACE_NAME("flush commands");
- surface->getCanvas()->flush();
+ surface->flushAndSubmit();
Properties::skpCaptureEnabled = previousSkpEnabled;
}
@@ -587,14 +588,23 @@ void SkiaPipeline::dumpResourceCacheUsage() const {
void SkiaPipeline::setSurfaceColorProperties(ColorMode colorMode) {
mColorMode = colorMode;
- if (colorMode == ColorMode::SRGB) {
- mSurfaceColorType = SkColorType::kN32_SkColorType;
- mSurfaceColorSpace = SkColorSpace::MakeSRGB();
- } else if (colorMode == ColorMode::WideColorGamut) {
- mSurfaceColorType = DeviceInfo::get()->getWideColorType();
- mSurfaceColorSpace = DeviceInfo::get()->getWideColorSpace();
- } else {
- LOG_ALWAYS_FATAL("Unreachable: unsupported color mode.");
+ switch (colorMode) {
+ case ColorMode::Default:
+ mSurfaceColorType = SkColorType::kN32_SkColorType;
+ mSurfaceColorSpace = SkColorSpace::MakeSRGB();
+ break;
+ case ColorMode::WideColorGamut:
+ mSurfaceColorType = DeviceInfo::get()->getWideColorType();
+ mSurfaceColorSpace = DeviceInfo::get()->getWideColorSpace();
+ break;
+ case ColorMode::Hdr:
+ mSurfaceColorType = SkColorType::kRGBA_F16_SkColorType;
+ mSurfaceColorSpace = SkColorSpace::MakeRGB(GetPQSkTransferFunction(), SkNamedGamut::kRec2020);
+ break;
+ case ColorMode::Hdr10:
+ mSurfaceColorType = SkColorType::kRGBA_1010102_SkColorType;
+ mSurfaceColorSpace = SkColorSpace::MakeRGB(GetPQSkTransferFunction(), SkNamedGamut::kRec2020);
+ break;
}
}
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h
index 8341164edc19..100bfb6b159a 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.h
@@ -50,7 +50,7 @@ public:
bool createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator,
ErrorHandler* errorHandler) override;
- void setSurfaceColorProperties(renderthread::ColorMode colorMode) override;
+ void setSurfaceColorProperties(ColorMode colorMode) override;
SkColorType getSurfaceColorType() const override { return mSurfaceColorType; }
sk_sp<SkColorSpace> getSurfaceColorSpace() override { return mSurfaceColorSpace; }
@@ -76,7 +76,7 @@ protected:
renderthread::RenderThread& mRenderThread;
- renderthread::ColorMode mColorMode = renderthread::ColorMode::SRGB;
+ ColorMode mColorMode = ColorMode::Default;
SkColorType mSurfaceColorType;
sk_sp<SkColorSpace> mSurfaceColorSpace;
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index d67cf8c9c73f..e292cbdd101f 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -57,7 +57,7 @@ void SkiaRecordingCanvas::initDisplayList(uirenderer::RenderNode* renderNode, in
uirenderer::DisplayList* SkiaRecordingCanvas::finishRecording() {
// close any existing chunks if necessary
- insertReorderBarrier(false);
+ enableZ(false);
mRecorder.restoreToCount(1);
return mDisplayList.release();
}
@@ -85,8 +85,8 @@ void SkiaRecordingCanvas::drawCircle(uirenderer::CanvasPropertyPrimitive* x,
drawDrawable(mDisplayList->allocateDrawable<AnimatedCircle>(x, y, radius, paint));
}
-void SkiaRecordingCanvas::insertReorderBarrier(bool enableReorder) {
- if (mCurrentBarrier && enableReorder) {
+void SkiaRecordingCanvas::enableZ(bool enableZ) {
+ if (mCurrentBarrier && enableZ) {
// Already in a re-order section, nothing to do
return;
}
@@ -98,7 +98,7 @@ void SkiaRecordingCanvas::insertReorderBarrier(bool enableReorder) {
mCurrentBarrier = nullptr;
drawDrawable(drawable);
}
- if (enableReorder) {
+ if (enableZ) {
mCurrentBarrier =
mDisplayList->allocateDrawable<StartReorderBarrierDrawable>(mDisplayList.get());
drawDrawable(mCurrentBarrier);
@@ -132,23 +132,6 @@ void SkiaRecordingCanvas::drawRenderNode(uirenderer::RenderNode* renderNode) {
}
}
-
-void SkiaRecordingCanvas::callDrawGLFunction(Functor* functor,
- uirenderer::GlFunctorLifecycleListener* listener) {
-#ifdef __ANDROID__ // Layoutlib does not support GL, Vulcan etc.
- FunctorDrawable* functorDrawable;
- if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
- functorDrawable = mDisplayList->allocateDrawable<VkInteropFunctorDrawable>(
- functor, listener, asSkCanvas());
- } else {
- functorDrawable =
- mDisplayList->allocateDrawable<GLFunctorDrawable>(functor, listener, asSkCanvas());
- }
- mDisplayList->mChildFunctors.push_back(functorDrawable);
- drawDrawable(functorDrawable);
-#endif
-}
-
void SkiaRecordingCanvas::drawWebViewFunctor(int functor) {
#ifdef __ANDROID__ // Layoutlib does not support GL, Vulcan etc.
FunctorDrawable* functorDrawable;
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
index bd5274c94e75..83e934974afd 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
@@ -69,11 +69,10 @@ public:
virtual void drawVectorDrawable(VectorDrawableRoot* vectorDrawable) override;
- virtual void insertReorderBarrier(bool enableReorder) override;
+ virtual void enableZ(bool enableZ) override;
virtual void drawLayer(uirenderer::DeferredLayerUpdater* layerHandle) override;
virtual void drawRenderNode(uirenderer::RenderNode* renderNode) override;
- virtual void callDrawGLFunction(Functor* functor,
- uirenderer::GlFunctorLifecycleListener* listener) override;
+
void drawWebViewFunctor(int functor) override;
private:
diff --git a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
index 68f111752a4c..50b45e6eb7ec 100644
--- a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
@@ -20,7 +20,7 @@
#include <GrBackendDrawableInfo.h>
#include <SkAndroidFrameworkUtils.h>
#include <SkImage.h>
-#include "include/private/SkM44.h"
+#include <SkM44.h>
#include <utils/Color.h>
#include <utils/Trace.h>
#include <utils/TraceUtils.h>
@@ -121,12 +121,7 @@ std::unique_ptr<FunctorDrawable::GpuDrawHandler> VkFunctorDrawable::onSnapGpuDra
return nullptr;
}
std::unique_ptr<VkFunctorDrawHandler> draw;
- if (mAnyFunctor.index() == 0) {
- return std::make_unique<VkFunctorDrawHandler>(std::get<0>(mAnyFunctor).handle, matrix, clip,
- image_info);
- } else {
- LOG_ALWAYS_FATAL("Not implemented");
- }
+ return std::make_unique<VkFunctorDrawHandler>(mWebViewHandle, matrix, clip, image_info);
}
} // namespace skiapipeline
diff --git a/libs/hwui/pipeline/skia/VkFunctorDrawable.h b/libs/hwui/pipeline/skia/VkFunctorDrawable.h
index d3f97773b91d..fbfc6e76595e 100644
--- a/libs/hwui/pipeline/skia/VkFunctorDrawable.h
+++ b/libs/hwui/pipeline/skia/VkFunctorDrawable.h
@@ -19,7 +19,6 @@
#include "FunctorDrawable.h"
#include <SkImageInfo.h>
-#include <ui/GraphicBuffer.h>
#include <utils/RefBase.h>
namespace android {
diff --git a/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp
index 241d3708def5..403d9075dbd1 100644
--- a/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp
@@ -15,23 +15,24 @@
*/
#include "VkInteropFunctorDrawable.h"
-#include <private/hwui/DrawGlInfo.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <GLES3/gl3.h>
+#include <private/hwui/DrawGlInfo.h>
#include <utils/Color.h>
+#include <utils/GLUtils.h>
#include <utils/Trace.h>
#include <utils/TraceUtils.h>
+
#include <thread>
+
#include "renderthread/EglManager.h"
#include "thread/ThreadBase.h"
#include "utils/TimeUtils.h"
-#include <EGL/eglext.h>
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-#include <GLES3/gl3.h>
-
-#include <utils/GLUtils.h>
-
namespace android {
namespace uirenderer {
namespace skiapipeline {
@@ -75,20 +76,23 @@ void VkInteropFunctorDrawable::onDraw(SkCanvas* canvas) {
SkImageInfo surfaceInfo = canvas->imageInfo();
- if (!mFrameBuffer.get() || mFBInfo != surfaceInfo) {
+ if (mFrameBuffer == nullptr || mFBInfo != surfaceInfo) {
// Buffer will be used as an OpenGL ES render target.
- mFrameBuffer = new GraphicBuffer(
- // TODO: try to reduce the size of the buffer: possibly by using clip bounds.
- static_cast<uint32_t>(surfaceInfo.width()),
- static_cast<uint32_t>(surfaceInfo.height()),
- ColorTypeToPixelFormat(surfaceInfo.colorType()),
- GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_NEVER |
- GraphicBuffer::USAGE_SW_READ_NEVER | GraphicBuffer::USAGE_HW_RENDER,
- std::string("VkInteropFunctorDrawable::onDraw pid [") + std::to_string(getpid()) +
- "]");
- status_t error = mFrameBuffer->initCheck();
- if (error < 0) {
- ALOGW("VkInteropFunctorDrawable::onDraw() failed in GraphicBuffer.create()");
+ AHardwareBuffer_Desc desc = {
+ .width = static_cast<uint32_t>(surfaceInfo.width()),
+ .height = static_cast<uint32_t>(surfaceInfo.height()),
+ .layers = 1,
+ .format = ColorTypeToBufferFormat(surfaceInfo.colorType()),
+ .usage = AHARDWAREBUFFER_USAGE_CPU_READ_NEVER |
+ AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER |
+ AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE |
+ AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER,
+ };
+
+ mFrameBuffer = allocateAHardwareBuffer(desc);
+
+ if (!mFrameBuffer) {
+ ALOGW("VkInteropFunctorDrawable::onDraw() failed in AHardwareBuffer_allocate()");
return;
}
@@ -106,7 +110,7 @@ void VkInteropFunctorDrawable::onDraw(SkCanvas* canvas) {
uirenderer::renderthread::EglManager::eglErrorString());
// We use an EGLImage to access the content of the GraphicBuffer
// The EGL image is later bound to a 2D texture
- EGLClientBuffer clientBuffer = (EGLClientBuffer)mFrameBuffer->getNativeBuffer();
+ const EGLClientBuffer clientBuffer = eglGetNativeClientBufferANDROID(mFrameBuffer.get());
AutoEglImage autoImage(display, clientBuffer);
if (autoImage.image == EGL_NO_IMAGE_KHR) {
ALOGW("Could not create EGL image, err =%s",
@@ -121,7 +125,7 @@ void VkInteropFunctorDrawable::onDraw(SkCanvas* canvas) {
glBindTexture(GL_TEXTURE_2D, 0);
DrawGlInfo info;
- SkM44 mat4(canvas->experimental_getLocalToDevice());
+ SkM44 mat4(canvas->getLocalToDevice());
SkIRect clipBounds = canvas->getDeviceClipBounds();
info.clipLeft = clipBounds.fLeft;
@@ -151,11 +155,7 @@ void VkInteropFunctorDrawable::onDraw(SkCanvas* canvas) {
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
- if (mAnyFunctor.index() == 0) {
- std::get<0>(mAnyFunctor).handle->drawGl(info);
- } else {
- (*(std::get<1>(mAnyFunctor).functor))(DrawGlInfo::kModeDraw, &info);
- }
+ mWebViewHandle->drawGl(info);
EGLSyncKHR glDrawFinishedFence =
eglCreateSyncKHR(eglGetCurrentDisplay(), EGL_SYNC_FENCE_KHR, NULL);
@@ -179,22 +179,13 @@ void VkInteropFunctorDrawable::onDraw(SkCanvas* canvas) {
// drawing into the offscreen surface, so we need to reset it here.
canvas->resetMatrix();
- auto functorImage = SkImage::MakeFromAHardwareBuffer(
- reinterpret_cast<AHardwareBuffer*>(mFrameBuffer.get()), kPremul_SkAlphaType,
- canvas->imageInfo().refColorSpace(), kBottomLeft_GrSurfaceOrigin);
+ auto functorImage = SkImage::MakeFromAHardwareBuffer(mFrameBuffer.get(), kPremul_SkAlphaType,
+ canvas->imageInfo().refColorSpace(),
+ kBottomLeft_GrSurfaceOrigin);
canvas->drawImage(functorImage, 0, 0, &paint);
canvas->restore();
}
-VkInteropFunctorDrawable::~VkInteropFunctorDrawable() {
- if (auto lp = std::get_if<LegacyFunctor>(&mAnyFunctor)) {
- if (lp->listener) {
- ScopedDrawRequest _drawRequest{};
- lp->listener->onGlFunctorReleased(lp->functor);
- }
- }
-}
-
void VkInteropFunctorDrawable::syncFunctor(const WebViewSyncData& data) const {
ScopedDrawRequest _drawRequest{};
FunctorDrawable::syncFunctor(data);
diff --git a/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.h b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.h
index c47ee114263f..e6ea175929c0 100644
--- a/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.h
+++ b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.h
@@ -16,11 +16,12 @@
#pragma once
-#include "FunctorDrawable.h"
-
-#include <ui/GraphicBuffer.h>
+#include <android/hardware_buffer.h>
+#include <utils/NdkUtils.h>
#include <utils/RefBase.h>
+#include "FunctorDrawable.h"
+
namespace android {
namespace uirenderer {
@@ -34,7 +35,7 @@ class VkInteropFunctorDrawable : public FunctorDrawable {
public:
using FunctorDrawable::FunctorDrawable;
- virtual ~VkInteropFunctorDrawable();
+ virtual ~VkInteropFunctorDrawable() {}
static void vkInvokeFunctor(Functor* functor);
@@ -45,7 +46,7 @@ protected:
private:
// Variables below describe/store temporary offscreen buffer used for Vulkan pipeline.
- sp<GraphicBuffer> mFrameBuffer;
+ UniqueAHardwareBuffer mFrameBuffer;
SkImageInfo mFBInfo;
};
diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp
index 1e5877356e8d..b57dee4897ac 100644
--- a/libs/hwui/renderthread/CacheManager.cpp
+++ b/libs/hwui/renderthread/CacheManager.cpp
@@ -101,7 +101,7 @@ void CacheManager::trimMemory(TrimMemoryMode mode) {
return;
}
- mGrContext->flush();
+ mGrContext->flushAndSubmit();
switch (mode) {
case TrimMemoryMode::Complete:
@@ -122,14 +122,15 @@ void CacheManager::trimMemory(TrimMemoryMode mode) {
// We must sync the cpu to make sure deletions of resources still queued up on the GPU actually
// happen.
- mGrContext->flush(kSyncCpu_GrFlushFlag, 0, nullptr);
+ mGrContext->flush({});
+ mGrContext->submit(true);
}
void CacheManager::trimStaleResources() {
if (!mGrContext) {
return;
}
- mGrContext->flush();
+ mGrContext->flushAndSubmit();
mGrContext->purgeResourcesNotUsedInMs(std::chrono::seconds(30));
}
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index a362bd220936..13d544c68e95 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -174,7 +174,10 @@ void CanvasContext::setSurface(ANativeWindow* window, bool enableTimeout) {
} else {
mNativeSurface = nullptr;
}
+ setupPipelineSurface();
+}
+void CanvasContext::setupPipelineSurface() {
bool hasSurface = mRenderPipeline->setSurface(
mNativeSurface ? mNativeSurface->getNativeWindow() : nullptr, mSwapBehavior);
@@ -184,7 +187,7 @@ void CanvasContext::setSurface(ANativeWindow* window, bool enableTimeout) {
mFrameNumber = -1;
- if (window != nullptr && hasSurface) {
+ if (mNativeSurface != nullptr && hasSurface) {
mHaveNewSurface = true;
mSwapHistory.clear();
// Enable frame stats after the surface has been bound to the appropriate graphics API.
@@ -239,9 +242,9 @@ void CanvasContext::setOpaque(bool opaque) {
mOpaque = opaque;
}
-void CanvasContext::setWideGamut(bool wideGamut) {
- ColorMode colorMode = wideGamut ? ColorMode::WideColorGamut : ColorMode::SRGB;
- mRenderPipeline->setSurfaceColorProperties(colorMode);
+void CanvasContext::setColorMode(ColorMode mode) {
+ mRenderPipeline->setSurfaceColorProperties(mode);
+ setupPipelineSurface();
}
bool CanvasContext::makeCurrent() {
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 0f1b8aebf56c..cba710f01063 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -30,6 +30,7 @@
#include "renderthread/RenderTask.h"
#include "renderthread/RenderThread.h"
#include "utils/RingBuffer.h"
+#include "ColorMode.h"
#include <SkBitmap.h>
#include <SkRect.h>
@@ -119,7 +120,7 @@ public:
void setLightAlpha(uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha);
void setLightGeometry(const Vector3& lightCenter, float lightRadius);
void setOpaque(bool opaque);
- void setWideGamut(bool wideGamut);
+ void setColorMode(ColorMode mode);
bool makeCurrent();
void prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t syncQueued, RenderNode* target);
void draw();
@@ -170,9 +171,9 @@ public:
}
// Used to queue up work that needs to be completed before this frame completes
- ANDROID_API void enqueueFrameWork(std::function<void()>&& func);
+ void enqueueFrameWork(std::function<void()>&& func);
- ANDROID_API int64_t getFrameNumber();
+ int64_t getFrameNumber();
void waitOnFences();
@@ -211,6 +212,7 @@ private:
bool isSwapChainStuffed();
bool surfaceRequiresRedraw();
void setPresentTime();
+ void setupPipelineSurface();
SkRect computeDirtyRect(const Frame& frame, SkRect* dirty);
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index 5e0471c08d67..2a8aa8c3e5b7 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -76,6 +76,7 @@ static struct {
bool glColorSpace = false;
bool scRGB = false;
bool displayP3 = false;
+ bool hdr = false;
bool contextPriority = false;
bool surfacelessContext = false;
bool nativeFenceSync = false;
@@ -86,7 +87,8 @@ static struct {
EglManager::EglManager()
: mEglDisplay(EGL_NO_DISPLAY)
, mEglConfig(nullptr)
- , mEglConfigWideGamut(nullptr)
+ , mEglConfigF16(nullptr)
+ , mEglConfig1010102(nullptr)
, mEglContext(EGL_NO_CONTEXT)
, mPBufferSurface(EGL_NO_SURFACE)
, mCurrentSurface(EGL_NO_SURFACE)
@@ -136,15 +138,14 @@ void EglManager::initialize() {
LOG_ALWAYS_FATAL_IF(!DeviceInfo::get()->getWideColorSpace()->toXYZD50(&wideColorGamut),
"Could not get gamut matrix from wideColorSpace");
bool hasWideColorSpaceExtension = false;
- if (memcmp(&wideColorGamut, &SkNamedGamut::kDCIP3, sizeof(wideColorGamut)) == 0) {
+ if (memcmp(&wideColorGamut, &SkNamedGamut::kDisplayP3, sizeof(wideColorGamut)) == 0) {
hasWideColorSpaceExtension = EglExtensions.displayP3;
} else if (memcmp(&wideColorGamut, &SkNamedGamut::kSRGB, sizeof(wideColorGamut)) == 0) {
hasWideColorSpaceExtension = EglExtensions.scRGB;
} else {
LOG_ALWAYS_FATAL("Unsupported wide color space.");
}
- mHasWideColorGamutSupport = EglExtensions.glColorSpace && hasWideColorSpaceExtension &&
- mEglConfigWideGamut != EGL_NO_CONFIG_KHR;
+ mHasWideColorGamutSupport = EglExtensions.glColorSpace && hasWideColorSpaceExtension;
}
EGLConfig EglManager::load8BitsConfig(EGLDisplay display, EglManager::SwapBehavior swapBehavior) {
@@ -177,6 +178,35 @@ EGLConfig EglManager::load8BitsConfig(EGLDisplay display, EglManager::SwapBehavi
return config;
}
+EGLConfig EglManager::load1010102Config(EGLDisplay display, SwapBehavior swapBehavior) {
+ EGLint eglSwapBehavior =
+ (swapBehavior == SwapBehavior::Preserved) ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0;
+ // If we reached this point, we have a valid swap behavior
+ EGLint attribs[] = {EGL_RENDERABLE_TYPE,
+ EGL_OPENGL_ES2_BIT,
+ EGL_RED_SIZE,
+ 10,
+ EGL_GREEN_SIZE,
+ 10,
+ EGL_BLUE_SIZE,
+ 10,
+ EGL_ALPHA_SIZE,
+ 2,
+ EGL_DEPTH_SIZE,
+ 0,
+ EGL_STENCIL_SIZE,
+ STENCIL_BUFFER_SIZE,
+ EGL_SURFACE_TYPE,
+ EGL_WINDOW_BIT | eglSwapBehavior,
+ EGL_NONE};
+ EGLConfig config = EGL_NO_CONFIG_KHR;
+ EGLint numConfigs = 1;
+ if (!eglChooseConfig(display, attribs, &config, numConfigs, &numConfigs) || numConfigs != 1) {
+ return EGL_NO_CONFIG_KHR;
+ }
+ return config;
+}
+
EGLConfig EglManager::loadFP16Config(EGLDisplay display, SwapBehavior swapBehavior) {
EGLint eglSwapBehavior =
(swapBehavior == SwapBehavior::Preserved) ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0;
@@ -208,8 +238,12 @@ EGLConfig EglManager::loadFP16Config(EGLDisplay display, SwapBehavior swapBehavi
return config;
}
+extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
+
void EglManager::initExtensions() {
auto extensions = StringUtils::split(eglQueryString(mEglDisplay, EGL_EXTENSIONS));
+ auto extensionsAndroid =
+ StringUtils::split(eglQueryStringImplementationANDROID(mEglDisplay, EGL_EXTENSIONS));
// For our purposes we don't care if EGL_BUFFER_AGE is a result of
// EGL_EXT_buffer_age or EGL_KHR_partial_update as our usage is covered
@@ -226,11 +260,15 @@ void EglManager::initExtensions() {
EglExtensions.pixelFormatFloat = extensions.has("EGL_EXT_pixel_format_float");
EglExtensions.scRGB = extensions.has("EGL_EXT_gl_colorspace_scrgb");
EglExtensions.displayP3 = extensions.has("EGL_EXT_gl_colorspace_display_p3_passthrough");
+ EglExtensions.hdr = extensions.has("EGL_EXT_gl_colorspace_bt2020_pq");
EglExtensions.contextPriority = extensions.has("EGL_IMG_context_priority");
EglExtensions.surfacelessContext = extensions.has("EGL_KHR_surfaceless_context");
- EglExtensions.nativeFenceSync = extensions.has("EGL_ANDROID_native_fence_sync");
EglExtensions.fenceSync = extensions.has("EGL_KHR_fence_sync");
EglExtensions.waitSync = extensions.has("EGL_KHR_wait_sync");
+
+ // EGL_ANDROID_native_fence_sync is not exposed to applications, so access
+ // this through the private Android-specific query instead.
+ EglExtensions.nativeFenceSync = extensionsAndroid.has("EGL_ANDROID_native_fence_sync");
}
bool EglManager::hasEglContext() {
@@ -253,18 +291,20 @@ void EglManager::loadConfigs() {
LOG_ALWAYS_FATAL("Failed to choose config, error = %s", eglErrorString());
}
}
- SkColorType wideColorType = DeviceInfo::get()->getWideColorType();
// When we reach this point, we have a valid swap behavior
- if (wideColorType == SkColorType::kRGBA_F16_SkColorType && EglExtensions.pixelFormatFloat) {
- mEglConfigWideGamut = loadFP16Config(mEglDisplay, mSwapBehavior);
- if (mEglConfigWideGamut == EGL_NO_CONFIG_KHR) {
+ if (EglExtensions.pixelFormatFloat) {
+ mEglConfigF16 = loadFP16Config(mEglDisplay, mSwapBehavior);
+ if (mEglConfigF16 == EGL_NO_CONFIG_KHR) {
ALOGE("Device claims wide gamut support, cannot find matching config, error = %s",
eglErrorString());
EglExtensions.pixelFormatFloat = false;
}
- } else if (wideColorType == SkColorType::kN32_SkColorType) {
- mEglConfigWideGamut = load8BitsConfig(mEglDisplay, mSwapBehavior);
+ }
+ mEglConfig1010102 = load1010102Config(mEglDisplay, mSwapBehavior);
+ if (mEglConfig1010102 == EGL_NO_CONFIG_KHR) {
+ ALOGW("Failed to initialize 101010-2 format, error = %s",
+ eglErrorString());
}
}
@@ -304,8 +344,9 @@ Result<EGLSurface, EGLint> EglManager::createSurface(EGLNativeWindowType window,
sk_sp<SkColorSpace> colorSpace) {
LOG_ALWAYS_FATAL_IF(!hasEglContext(), "Not initialized");
- bool wideColorGamut = colorMode == ColorMode::WideColorGamut && mHasWideColorGamutSupport &&
- EglExtensions.noConfigContext;
+ if (!mHasWideColorGamutSupport || !EglExtensions.noConfigContext) {
+ colorMode = ColorMode::Default;
+ }
// The color space we want to use depends on whether linear blending is turned
// on and whether the app has requested wide color gamut rendering. When wide
@@ -331,26 +372,47 @@ Result<EGLSurface, EGLint> EglManager::createSurface(EGLNativeWindowType window,
// list is considered empty if the first entry is EGL_NONE
EGLint attribs[] = {EGL_NONE, EGL_NONE, EGL_NONE};
+ EGLConfig config = mEglConfig;
+ if (DeviceInfo::get()->getWideColorType() == kRGBA_F16_SkColorType) {
+ if (mEglConfigF16 == EGL_NO_CONFIG_KHR) {
+ colorMode = ColorMode::Default;
+ } else {
+ config = mEglConfigF16;
+ }
+ }
if (EglExtensions.glColorSpace) {
attribs[0] = EGL_GL_COLORSPACE_KHR;
- if (wideColorGamut) {
- skcms_Matrix3x3 colorGamut;
- LOG_ALWAYS_FATAL_IF(!colorSpace->toXYZD50(&colorGamut),
- "Could not get gamut matrix from color space");
- if (memcmp(&colorGamut, &SkNamedGamut::kDCIP3, sizeof(colorGamut)) == 0) {
- attribs[1] = EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT;
- } else if (memcmp(&colorGamut, &SkNamedGamut::kSRGB, sizeof(colorGamut)) == 0) {
- attribs[1] = EGL_GL_COLORSPACE_SCRGB_EXT;
- } else {
- LOG_ALWAYS_FATAL("Unreachable: unsupported wide color space.");
+ switch (colorMode) {
+ case ColorMode::Default:
+ attribs[1] = EGL_GL_COLORSPACE_LINEAR_KHR;
+ break;
+ case ColorMode::WideColorGamut: {
+ skcms_Matrix3x3 colorGamut;
+ LOG_ALWAYS_FATAL_IF(!colorSpace->toXYZD50(&colorGamut),
+ "Could not get gamut matrix from color space");
+ if (memcmp(&colorGamut, &SkNamedGamut::kDisplayP3, sizeof(colorGamut)) == 0) {
+ attribs[1] = EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT;
+ } else if (memcmp(&colorGamut, &SkNamedGamut::kSRGB, sizeof(colorGamut)) == 0) {
+ attribs[1] = EGL_GL_COLORSPACE_SCRGB_EXT;
+ } else if (memcmp(&colorGamut, &SkNamedGamut::kRec2020, sizeof(colorGamut)) == 0) {
+ attribs[1] = EGL_GL_COLORSPACE_BT2020_PQ_EXT;
+ } else {
+ LOG_ALWAYS_FATAL("Unreachable: unsupported wide color space.");
+ }
+ break;
}
- } else {
- attribs[1] = EGL_GL_COLORSPACE_LINEAR_KHR;
+ case ColorMode::Hdr:
+ config = mEglConfigF16;
+ attribs[1] = EGL_GL_COLORSPACE_BT2020_PQ_EXT;
+ break;
+ case ColorMode::Hdr10:
+ config = mEglConfig1010102;
+ attribs[1] = EGL_GL_COLORSPACE_BT2020_PQ_EXT;
+ break;
}
}
- EGLSurface surface = eglCreateWindowSurface(
- mEglDisplay, wideColorGamut ? mEglConfigWideGamut : mEglConfig, window, attribs);
+ EGLSurface surface = eglCreateWindowSurface(mEglDisplay, config, window, attribs);
if (surface == EGL_NO_SURFACE) {
return Error<EGLint>{eglGetError()};
}
diff --git a/libs/hwui/renderthread/EglManager.h b/libs/hwui/renderthread/EglManager.h
index a893e245b214..69f3ed014c53 100644
--- a/libs/hwui/renderthread/EglManager.h
+++ b/libs/hwui/renderthread/EglManager.h
@@ -21,7 +21,6 @@
#include <SkImageInfo.h>
#include <SkRect.h>
#include <cutils/compiler.h>
-#include <ui/GraphicBuffer.h>
#include <utils/StrongPointer.h>
#include "IRenderPipeline.h"
@@ -89,6 +88,7 @@ private:
static EGLConfig load8BitsConfig(EGLDisplay display, SwapBehavior swapBehavior);
static EGLConfig loadFP16Config(EGLDisplay display, SwapBehavior swapBehavior);
+ static EGLConfig load1010102Config(EGLDisplay display, SwapBehavior swapBehavior);
void initExtensions();
void createPBufferSurface();
@@ -98,7 +98,8 @@ private:
EGLDisplay mEglDisplay;
EGLConfig mEglConfig;
- EGLConfig mEglConfigWideGamut;
+ EGLConfig mEglConfigF16;
+ EGLConfig mEglConfig1010102;
EGLContext mEglContext;
EGLSurface mPBufferSurface;
EGLSurface mCurrentSurface;
diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h
index c3c22869a42f..a04738d6a6f0 100644
--- a/libs/hwui/renderthread/IRenderPipeline.h
+++ b/libs/hwui/renderthread/IRenderPipeline.h
@@ -22,6 +22,7 @@
#include "Lighting.h"
#include "SwapBehavior.h"
#include "hwui/Bitmap.h"
+#include "ColorMode.h"
#include <SkRect.h>
#include <utils/RefBase.h>
@@ -42,16 +43,6 @@ namespace renderthread {
enum class MakeCurrentResult { AlreadyCurrent, Failed, Succeeded };
-enum class ColorMode {
- // SRGB means HWUI will produce buffer in SRGB color space.
- SRGB,
- // WideColorGamut means HWUI would support rendering scRGB non-linear into
- // a signed buffer with enough range to support the wide color gamut of the
- // display.
- WideColorGamut,
- // Hdr
-};
-
class Frame;
class IRenderPipeline {
diff --git a/libs/hwui/renderthread/ReliableSurface.cpp b/libs/hwui/renderthread/ReliableSurface.cpp
index dcf1fc189588..c29cc11fa7ea 100644
--- a/libs/hwui/renderthread/ReliableSurface.cpp
+++ b/libs/hwui/renderthread/ReliableSurface.cpp
@@ -149,21 +149,25 @@ ANativeWindowBuffer* ReliableSurface::acquireFallbackBuffer(int error) {
return AHardwareBuffer_to_ANativeWindowBuffer(mScratchBuffer.get());
}
- AHardwareBuffer_Desc desc;
- desc.usage = mUsage;
- desc.format = mFormat;
- desc.width = 1;
- desc.height = 1;
- desc.layers = 1;
- desc.rfu0 = 0;
- desc.rfu1 = 0;
- AHardwareBuffer* newBuffer = nullptr;
- int err = AHardwareBuffer_allocate(&desc, &newBuffer);
- if (err) {
+ AHardwareBuffer_Desc desc = AHardwareBuffer_Desc{
+ .usage = mUsage,
+ .format = mFormat,
+ .width = 1,
+ .height = 1,
+ .layers = 1,
+ .rfu0 = 0,
+ .rfu1 = 0,
+ };
+
+ AHardwareBuffer* newBuffer;
+ int result = AHardwareBuffer_allocate(&desc, &newBuffer);
+
+ if (result != NO_ERROR) {
// Allocate failed, that sucks
- ALOGW("Failed to allocate scratch buffer, error=%d", err);
+ ALOGW("Failed to allocate scratch buffer, error=%d", result);
return nullptr;
}
+
mScratchBuffer.reset(newBuffer);
return AHardwareBuffer_to_ANativeWindowBuffer(newBuffer);
}
diff --git a/libs/hwui/renderthread/ReliableSurface.h b/libs/hwui/renderthread/ReliableSurface.h
index f699eb1fe6b3..41969e776fc8 100644
--- a/libs/hwui/renderthread/ReliableSurface.h
+++ b/libs/hwui/renderthread/ReliableSurface.h
@@ -21,6 +21,7 @@
#include <apex/window.h>
#include <utils/Errors.h>
#include <utils/Macros.h>
+#include <utils/NdkUtils.h>
#include <utils/StrongPointer.h>
#include <memory>
@@ -67,8 +68,7 @@ private:
uint64_t mUsage = AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER;
AHardwareBuffer_Format mFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
- std::unique_ptr<AHardwareBuffer, void (*)(AHardwareBuffer*)> mScratchBuffer{
- nullptr, AHardwareBuffer_release};
+ UniqueAHardwareBuffer mScratchBuffer;
ANativeWindowBuffer* mReservedBuffer = nullptr;
base::unique_fd mReservedFenceFd;
bool mHasDequeuedBuffer = false;
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index b66a13d1efda..aad0cca80cdc 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -109,8 +109,8 @@ void RenderProxy::setOpaque(bool opaque) {
mRenderThread.queue().post([=]() { mContext->setOpaque(opaque); });
}
-void RenderProxy::setWideGamut(bool wideGamut) {
- mRenderThread.queue().post([=]() { mContext->setWideGamut(wideGamut); });
+void RenderProxy::setColorMode(ColorMode mode) {
+ mRenderThread.queue().post([=]() { mContext->setColorMode(mode); });
}
int64_t* RenderProxy::frameInfo() {
@@ -128,20 +128,6 @@ void RenderProxy::destroy() {
mRenderThread.queue().runSync([=]() { mContext->destroy(); });
}
-void RenderProxy::invokeFunctor(Functor* functor, bool waitForCompletion) {
- ATRACE_CALL();
- RenderThread& thread = RenderThread::getInstance();
- auto invoke = [&thread, functor]() { CanvasContext::invokeFunctor(thread, functor); };
- if (waitForCompletion) {
- // waitForCompletion = true is expected to be fairly rare and only
- // happen in destruction. Thus it should be fine to temporarily
- // create a Mutex
- thread.queue().runSync(std::move(invoke));
- } else {
- thread.queue().post(std::move(invoke));
- }
-}
-
void RenderProxy::destroyFunctor(int functor) {
ATRACE_CALL();
RenderThread& thread = RenderThread::getInstance();
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 3baeb2f7a476..33dabc9895b1 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -24,6 +24,7 @@
#include "../FrameMetricsObserver.h"
#include "../IContextFactory.h"
+#include "ColorMode.h"
#include "DrawFrameTask.h"
#include "SwapBehavior.h"
#include "hwui/Bitmap.h"
@@ -60,69 +61,67 @@ enum {
* references RenderProxy fields. This is safe as RenderProxy cannot
* be deleted if it is blocked inside a call.
*/
-class ANDROID_API RenderProxy {
+class RenderProxy {
public:
- ANDROID_API RenderProxy(bool opaque, RenderNode* rootNode, IContextFactory* contextFactory);
- ANDROID_API virtual ~RenderProxy();
+ RenderProxy(bool opaque, RenderNode* rootNode, IContextFactory* contextFactory);
+ virtual ~RenderProxy();
// Won't take effect until next EGLSurface creation
- ANDROID_API void setSwapBehavior(SwapBehavior swapBehavior);
- ANDROID_API bool loadSystemProperties();
- ANDROID_API void setName(const char* name);
-
- ANDROID_API void setSurface(ANativeWindow* window, bool enableTimeout = true);
- ANDROID_API void allocateBuffers();
- ANDROID_API bool pause();
- ANDROID_API void setStopped(bool stopped);
- ANDROID_API void setLightAlpha(uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha);
- ANDROID_API void setLightGeometry(const Vector3& lightCenter, float lightRadius);
- ANDROID_API void setOpaque(bool opaque);
- ANDROID_API void setWideGamut(bool wideGamut);
- ANDROID_API int64_t* frameInfo();
- ANDROID_API int syncAndDrawFrame();
- ANDROID_API void destroy();
-
- ANDROID_API static void invokeFunctor(Functor* functor, bool waitForCompletion);
+ void setSwapBehavior(SwapBehavior swapBehavior);
+ bool loadSystemProperties();
+ void setName(const char* name);
+
+ void setSurface(ANativeWindow* window, bool enableTimeout = true);
+ void allocateBuffers();
+ bool pause();
+ void setStopped(bool stopped);
+ void setLightAlpha(uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha);
+ void setLightGeometry(const Vector3& lightCenter, float lightRadius);
+ void setOpaque(bool opaque);
+ void setColorMode(ColorMode mode);
+ int64_t* frameInfo();
+ int syncAndDrawFrame();
+ void destroy();
+
static void destroyFunctor(int functor);
- ANDROID_API DeferredLayerUpdater* createTextureLayer();
- ANDROID_API void buildLayer(RenderNode* node);
- ANDROID_API bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap& bitmap);
- ANDROID_API void pushLayerUpdate(DeferredLayerUpdater* layer);
- ANDROID_API void cancelLayerUpdate(DeferredLayerUpdater* layer);
- ANDROID_API void detachSurfaceTexture(DeferredLayerUpdater* layer);
+ DeferredLayerUpdater* createTextureLayer();
+ void buildLayer(RenderNode* node);
+ bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap& bitmap);
+ void pushLayerUpdate(DeferredLayerUpdater* layer);
+ void cancelLayerUpdate(DeferredLayerUpdater* layer);
+ void detachSurfaceTexture(DeferredLayerUpdater* layer);
- ANDROID_API void destroyHardwareResources();
- ANDROID_API static void trimMemory(int level);
- ANDROID_API static void overrideProperty(const char* name, const char* value);
+ void destroyHardwareResources();
+ static void trimMemory(int level);
+ static void overrideProperty(const char* name, const char* value);
- ANDROID_API void fence();
- ANDROID_API static int maxTextureSize();
- ANDROID_API void stopDrawing();
- ANDROID_API void notifyFramePending();
+ void fence();
+ static int maxTextureSize();
+ void stopDrawing();
+ void notifyFramePending();
- ANDROID_API void dumpProfileInfo(int fd, int dumpFlags);
+ void dumpProfileInfo(int fd, int dumpFlags);
// Not exported, only used for testing
void resetProfileInfo();
uint32_t frameTimePercentile(int p);
- ANDROID_API static void dumpGraphicsMemory(int fd);
+ static void dumpGraphicsMemory(int fd);
- ANDROID_API static void rotateProcessStatsBuffer();
- ANDROID_API static void setProcessStatsBuffer(int fd);
- ANDROID_API int getRenderThreadTid();
+ static void rotateProcessStatsBuffer();
+ static void setProcessStatsBuffer(int fd);
+ int getRenderThreadTid();
- ANDROID_API void addRenderNode(RenderNode* node, bool placeFront);
- ANDROID_API void removeRenderNode(RenderNode* node);
- ANDROID_API void drawRenderNode(RenderNode* node);
- ANDROID_API void setContentDrawBounds(int left, int top, int right, int bottom);
- ANDROID_API void setPictureCapturedCallback(
- const std::function<void(sk_sp<SkPicture>&&)>& callback);
- ANDROID_API void setFrameCallback(std::function<void(int64_t)>&& callback);
- ANDROID_API void setFrameCompleteCallback(std::function<void(int64_t)>&& callback);
+ void addRenderNode(RenderNode* node, bool placeFront);
+ void removeRenderNode(RenderNode* node);
+ void drawRenderNode(RenderNode* node);
+ void setContentDrawBounds(int left, int top, int right, int bottom);
+ void setPictureCapturedCallback(const std::function<void(sk_sp<SkPicture>&&)>& callback);
+ void setFrameCallback(std::function<void(int64_t)>&& callback);
+ void setFrameCompleteCallback(std::function<void(int64_t)>&& callback);
- ANDROID_API void addFrameMetricsObserver(FrameMetricsObserver* observer);
- ANDROID_API void removeFrameMetricsObserver(FrameMetricsObserver* observer);
- ANDROID_API void setForceDark(bool enable);
+ void addFrameMetricsObserver(FrameMetricsObserver* observer);
+ void removeFrameMetricsObserver(FrameMetricsObserver* observer);
+ void setForceDark(bool enable);
/**
* Sets a render-ahead depth on the backing renderer. This will increase latency by
@@ -139,17 +138,17 @@ public:
*
* @param renderAhead How far to render ahead, must be in the range [0..2]
*/
- ANDROID_API void setRenderAheadDepth(int renderAhead);
+ void setRenderAheadDepth(int renderAhead);
- ANDROID_API static int copySurfaceInto(ANativeWindow* window, int left, int top, int right,
+ static int copySurfaceInto(ANativeWindow* window, int left, int top, int right,
int bottom, SkBitmap* bitmap);
- ANDROID_API static void prepareToDraw(Bitmap& bitmap);
+ static void prepareToDraw(Bitmap& bitmap);
static int copyHWBitmapInto(Bitmap* hwBitmap, SkBitmap* bitmap);
- ANDROID_API static void disableVsync();
+ static void disableVsync();
- ANDROID_API static void preload();
+ static void preload();
private:
RenderThread& mRenderThread;
diff --git a/libs/hwui/renderthread/RenderTask.h b/libs/hwui/renderthread/RenderTask.h
index c56a3578ad58..3e3a381d65fe 100644
--- a/libs/hwui/renderthread/RenderTask.h
+++ b/libs/hwui/renderthread/RenderTask.h
@@ -45,12 +45,12 @@ namespace renderthread {
* malloc/free churn of small objects?
*/
-class ANDROID_API RenderTask {
+class RenderTask {
public:
- ANDROID_API RenderTask() : mNext(nullptr), mRunAt(0) {}
- ANDROID_API virtual ~RenderTask() {}
+ RenderTask() : mNext(nullptr), mRunAt(0) {}
+ virtual ~RenderTask() {}
- ANDROID_API virtual void run() = 0;
+ virtual void run() = 0;
RenderTask* mNext;
nsecs_t mRunAt; // nano-seconds on the SYSTEM_TIME_MONOTONIC clock
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 206b58f62ea7..565fb61c8994 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -190,7 +190,7 @@ void RenderThread::requireGlContext() {
auto glesVersion = reinterpret_cast<const char*>(glGetString(GL_VERSION));
auto size = glesVersion ? strlen(glesVersion) : -1;
cacheManager().configureContext(&options, glesVersion, size);
- sk_sp<GrContext> grContext(GrContext::MakeGL(std::move(glInterface), options));
+ sk_sp<GrDirectContext> grContext(GrDirectContext::MakeGL(std::move(glInterface), options));
LOG_ALWAYS_FATAL_IF(!grContext.get());
setGrContext(grContext);
}
@@ -204,7 +204,7 @@ void RenderThread::requireVkContext() {
initGrContextOptions(options);
auto vkDriverVersion = mVkManager->getDriverVersion();
cacheManager().configureContext(&options, &vkDriverVersion, sizeof(vkDriverVersion));
- sk_sp<GrContext> grContext = mVkManager->createContext(options);
+ sk_sp<GrDirectContext> grContext = mVkManager->createContext(options);
LOG_ALWAYS_FATAL_IF(!grContext.get());
setGrContext(grContext);
}
@@ -263,7 +263,7 @@ Readback& RenderThread::readback() {
return *mReadback;
}
-void RenderThread::setGrContext(sk_sp<GrContext> context) {
+void RenderThread::setGrContext(sk_sp<GrDirectContext> context) {
mCacheManager->reset(context);
if (mGrContext) {
mRenderState->onContextDestroyed();
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index 8be46a6d16e1..b8ce55650516 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -17,7 +17,7 @@
#ifndef RENDERTHREAD_H_
#define RENDERTHREAD_H_
-#include <GrContext.h>
+#include <GrDirectContext.h>
#include <SkBitmap.h>
#include <apex/choreographer.h>
#include <cutils/compiler.h>
@@ -88,7 +88,7 @@ class RenderThread : private ThreadBase {
public:
// Sets a callback that fires before any RenderThread setup has occurred.
- ANDROID_API static void setOnStartHook(JVMAttachHook onStartHook);
+ static void setOnStartHook(JVMAttachHook onStartHook);
static JVMAttachHook getOnStartHook();
WorkQueue& queue() { return ThreadBase::queue(); }
@@ -106,8 +106,8 @@ public:
ProfileDataContainer& globalProfileData() { return mGlobalProfileData; }
Readback& readback();
- GrContext* getGrContext() const { return mGrContext.get(); }
- void setGrContext(sk_sp<GrContext> cxt);
+ GrDirectContext* getGrContext() const { return mGrContext.get(); }
+ void setGrContext(sk_sp<GrDirectContext> cxt);
CacheManager& cacheManager() { return *mCacheManager; }
VulkanManager& vulkanManager() { return *mVkManager; }
@@ -186,7 +186,7 @@ private:
ProfileDataContainer mGlobalProfileData;
Readback* mReadback = nullptr;
- sk_sp<GrContext> mGrContext;
+ sk_sp<GrDirectContext> mGrContext;
CacheManager* mCacheManager;
VulkanManager* mVkManager;
};
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index ba70afc8b8d2..249936eb485e 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -20,7 +20,7 @@
#include <EGL/eglext.h>
#include <GrBackendSemaphore.h>
#include <GrBackendSurface.h>
-#include <GrContext.h>
+#include <GrDirectContext.h>
#include <GrTypes.h>
#include <android/sync.h>
#include <ui/FatVector.h>
@@ -369,7 +369,7 @@ void VulkanManager::initialize() {
}
}
-sk_sp<GrContext> VulkanManager::createContext(const GrContextOptions& options) {
+sk_sp<GrDirectContext> VulkanManager::createContext(const GrContextOptions& options) {
auto getProc = [](const char* proc_name, VkInstance instance, VkDevice device) {
if (device != VK_NULL_HANDLE) {
return vkGetDeviceProcAddr(device, proc_name);
@@ -388,7 +388,7 @@ sk_sp<GrContext> VulkanManager::createContext(const GrContextOptions& options) {
backendContext.fDeviceFeatures2 = &mPhysicalDeviceFeatures2;
backendContext.fGetProc = std::move(getProc);
- return GrContext::MakeVulkan(backendContext, options);
+ return GrDirectContext::MakeVulkan(backendContext, options);
}
VkFunctorInitParams VulkanManager::getVkFunctorInitParams() const {
@@ -459,7 +459,7 @@ Frame VulkanManager::dequeueNextBuffer(VulkanSurface* surface) {
// The following flush blocks the GPU immediately instead of waiting for other
// drawing ops. It seems dequeue_fence is not respected otherwise.
// TODO: remove the flush after finding why backendSemaphore is not working.
- bufferInfo->skSurface->flush();
+ bufferInfo->skSurface->flushAndSubmit();
}
}
}
@@ -525,9 +525,15 @@ void VulkanManager::swapBuffers(VulkanSurface* surface, const SkRect& dirtyRect)
int fenceFd = -1;
DestroySemaphoreInfo* destroyInfo =
new DestroySemaphoreInfo(mDestroySemaphore, mDevice, semaphore);
+ GrFlushInfo flushInfo;
+ flushInfo.fNumSemaphores = 1;
+ flushInfo.fSignalSemaphores = &backendSemaphore;
+ flushInfo.fFinishedProc = destroy_semaphore;
+ flushInfo.fFinishedContext = destroyInfo;
GrSemaphoresSubmitted submitted = bufferInfo->skSurface->flush(
- SkSurface::BackendSurfaceAccess::kPresent, kNone_GrFlushFlags, 1, &backendSemaphore,
- destroy_semaphore, destroyInfo);
+ SkSurface::BackendSurfaceAccess::kPresent, flushInfo);
+ ALOGE_IF(!bufferInfo->skSurface->getContext(), "Surface is not backed by gpu");
+ bufferInfo->skSurface->getContext()->submit();
if (submitted == GrSemaphoresSubmitted::kYes) {
VkSemaphoreGetFdInfoKHR getFdInfo;
getFdInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR;
@@ -556,9 +562,11 @@ void VulkanManager::destroySurface(VulkanSurface* surface) {
delete surface;
}
-VulkanSurface* VulkanManager::createSurface(ANativeWindow* window, ColorMode colorMode,
+VulkanSurface* VulkanManager::createSurface(ANativeWindow* window,
+ ColorMode colorMode,
sk_sp<SkColorSpace> surfaceColorSpace,
- SkColorType surfaceColorType, GrContext* grContext,
+ SkColorType surfaceColorType,
+ GrDirectContext* grContext,
uint32_t extraBuffers) {
LOG_ALWAYS_FATAL_IF(!hasVkContext(), "Not initialized");
if (!window) {
@@ -569,7 +577,7 @@ VulkanSurface* VulkanManager::createSurface(ANativeWindow* window, ColorMode col
*this, extraBuffers);
}
-status_t VulkanManager::fenceWait(int fence, GrContext* grContext) {
+status_t VulkanManager::fenceWait(int fence, GrDirectContext* grContext) {
if (!hasVkContext()) {
ALOGE("VulkanManager::fenceWait: VkDevice not initialized");
return INVALID_OPERATION;
@@ -612,12 +620,12 @@ status_t VulkanManager::fenceWait(int fence, GrContext* grContext) {
// Skia takes ownership of the semaphore and will delete it once the wait has finished.
grContext->wait(1, &beSemaphore);
- grContext->flush();
+ grContext->flushAndSubmit();
return OK;
}
-status_t VulkanManager::createReleaseFence(int* nativeFence, GrContext* grContext) {
+status_t VulkanManager::createReleaseFence(int* nativeFence, GrDirectContext* grContext) {
*nativeFence = -1;
if (!hasVkContext()) {
ALOGE("VulkanManager::createReleaseFence: VkDevice not initialized");
@@ -648,8 +656,13 @@ status_t VulkanManager::createReleaseFence(int* nativeFence, GrContext* grContex
// Even if Skia fails to submit the semaphore, it will still call the destroy_semaphore callback
// which will remove its ref to the semaphore. The VulkanManager must still release its ref,
// when it is done with the semaphore.
- GrSemaphoresSubmitted submitted = grContext->flush(kNone_GrFlushFlags, 1, &backendSemaphore,
- destroy_semaphore, destroyInfo);
+ GrFlushInfo flushInfo;
+ flushInfo.fNumSemaphores = 1;
+ flushInfo.fSignalSemaphores = &backendSemaphore;
+ flushInfo.fFinishedProc = destroy_semaphore;
+ flushInfo.fFinishedContext = destroyInfo;
+ GrSemaphoresSubmitted submitted = grContext->flush(flushInfo);
+ grContext->submit();
if (submitted == GrSemaphoresSubmitted::kNo) {
ALOGE("VulkanManager::createReleaseFence: Failed to submit semaphore");
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index 8b19f13fdfb9..3f2df8d75d89 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -57,9 +57,11 @@ public:
bool hasVkContext() { return mDevice != VK_NULL_HANDLE; }
// Create and destroy functions for wrapping an ANativeWindow in a VulkanSurface
- VulkanSurface* createSurface(ANativeWindow* window, ColorMode colorMode,
+ VulkanSurface* createSurface(ANativeWindow* window,
+ ColorMode colorMode,
sk_sp<SkColorSpace> surfaceColorSpace,
- SkColorType surfaceColorType, GrContext* grContext,
+ SkColorType surfaceColorType,
+ GrDirectContext* grContext,
uint32_t extraBuffers);
void destroySurface(VulkanSurface* surface);
@@ -70,18 +72,18 @@ public:
void destroy();
// Inserts a wait on fence command into the Vulkan command buffer.
- status_t fenceWait(int fence, GrContext* grContext);
+ status_t fenceWait(int fence, GrDirectContext* grContext);
// Creates a fence that is signaled when all the pending Vulkan commands are finished on the
// GPU.
- status_t createReleaseFence(int* nativeFence, GrContext* grContext);
+ status_t createReleaseFence(int* nativeFence, GrDirectContext* grContext);
// Returned pointers are owned by VulkanManager.
// An instance of VkFunctorInitParams returned from getVkFunctorInitParams refers to
// the internal state of VulkanManager: VulkanManager must be alive to use the returned value.
VkFunctorInitParams getVkFunctorInitParams() const;
- sk_sp<GrContext> createContext(const GrContextOptions& options);
+ sk_sp<GrDirectContext> createContext(const GrContextOptions& options);
uint32_t getDriverVersion() const { return mDriverVersion; }
diff --git a/libs/hwui/renderthread/VulkanSurface.cpp b/libs/hwui/renderthread/VulkanSurface.cpp
index a7ea21d8c4de..1da09b454da7 100644
--- a/libs/hwui/renderthread/VulkanSurface.cpp
+++ b/libs/hwui/renderthread/VulkanSurface.cpp
@@ -200,16 +200,16 @@ bool VulkanSurface::InitializeWindowInfoStruct(ANativeWindow* window, ColorMode
"Could not get gamut matrix from color space");
if (memcmp(&surfaceGamut, &SkNamedGamut::kSRGB, sizeof(surfaceGamut)) == 0) {
outWindowInfo->dataspace = HAL_DATASPACE_V0_SCRGB;
- } else if (memcmp(&surfaceGamut, &SkNamedGamut::kDCIP3, sizeof(surfaceGamut)) == 0) {
+ } else if (memcmp(&surfaceGamut, &SkNamedGamut::kDisplayP3, sizeof(surfaceGamut)) == 0) {
outWindowInfo->dataspace = HAL_DATASPACE_DISPLAY_P3;
} else {
LOG_ALWAYS_FATAL("Unreachable: unsupported wide color space.");
}
}
- outWindowInfo->pixelFormat = ColorTypeToPixelFormat(colorType);
+ outWindowInfo->bufferFormat = ColorTypeToBufferFormat(colorType);
VkFormat vkPixelFormat = VK_FORMAT_R8G8B8A8_UNORM;
- if (outWindowInfo->pixelFormat == PIXEL_FORMAT_RGBA_FP16) {
+ if (outWindowInfo->bufferFormat == AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT) {
vkPixelFormat = VK_FORMAT_R16G16B16A16_SFLOAT;
}
@@ -263,10 +263,10 @@ bool VulkanSurface::InitializeWindowInfoStruct(ANativeWindow* window, ColorMode
bool VulkanSurface::UpdateWindow(ANativeWindow* window, const WindowInfo& windowInfo) {
ATRACE_CALL();
- int err = native_window_set_buffers_format(window, windowInfo.pixelFormat);
+ int err = native_window_set_buffers_format(window, windowInfo.bufferFormat);
if (err != 0) {
ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_format(%d) failed: %s (%d)",
- windowInfo.pixelFormat, strerror(-err), err);
+ windowInfo.bufferFormat, strerror(-err), err);
return false;
}
diff --git a/libs/hwui/renderthread/VulkanSurface.h b/libs/hwui/renderthread/VulkanSurface.h
index bd2362612a13..40a44b11c0bc 100644
--- a/libs/hwui/renderthread/VulkanSurface.h
+++ b/libs/hwui/renderthread/VulkanSurface.h
@@ -17,8 +17,6 @@
#include <system/graphics.h>
#include <system/window.h>
-#include <ui/BufferQueueDefs.h>
-#include <ui/PixelFormat.h>
#include <vulkan/vulkan.h>
#include <SkRefCnt.h>
@@ -91,7 +89,7 @@ private:
struct WindowInfo {
SkISize size;
- PixelFormat pixelFormat;
+ uint32_t bufferFormat;
android_dataspace dataspace;
int transform;
size_t bufferCount;
@@ -111,8 +109,13 @@ private:
static bool UpdateWindow(ANativeWindow* window, const WindowInfo& windowInfo);
void releaseBuffers();
+ // TODO: This number comes from ui/BufferQueueDefs. We're not pulling the
+ // header in so that we don't need to depend on libui, but we should share
+ // this constant somewhere. But right now it's okay to keep here because we
+ // can't safely change the slot count anyways.
+ static constexpr size_t kNumBufferSlots = 64;
// TODO: Just use a vector?
- NativeBufferInfo mNativeBuffers[android::BufferQueueDefs::NUM_BUFFER_SLOTS];
+ NativeBufferInfo mNativeBuffers[kNumBufferSlots];
sp<ANativeWindow> mNativeWindow;
WindowInfo mWindowInfo;
diff --git a/libs/hwui/service/GraphicsStatsService.cpp b/libs/hwui/service/GraphicsStatsService.cpp
index 644d5fbd5bf9..e4198017aee0 100644
--- a/libs/hwui/service/GraphicsStatsService.cpp
+++ b/libs/hwui/service/GraphicsStatsService.cpp
@@ -559,6 +559,7 @@ void GraphicsStatsService::finishDumpInMemory(Dump* dump, AStatsEventList* data,
AStatsEvent_writeBool(event, !lastFullDay);
AStatsEvent_build(event);
}
+ delete dump;
}
diff --git a/libs/hwui/service/GraphicsStatsService.h b/libs/hwui/service/GraphicsStatsService.h
index 59e21d039c9d..4063f749f808 100644
--- a/libs/hwui/service/GraphicsStatsService.h
+++ b/libs/hwui/service/GraphicsStatsService.h
@@ -44,18 +44,16 @@ public:
ProtobufStatsd,
};
- ANDROID_API static void saveBuffer(const std::string& path, const std::string& package,
- int64_t versionCode, int64_t startTime, int64_t endTime,
- const ProfileData* data);
-
- ANDROID_API static Dump* createDump(int outFd, DumpType type);
- ANDROID_API static void addToDump(Dump* dump, const std::string& path,
- const std::string& package, int64_t versionCode,
- int64_t startTime, int64_t endTime, const ProfileData* data);
- ANDROID_API static void addToDump(Dump* dump, const std::string& path);
- ANDROID_API static void finishDump(Dump* dump);
- ANDROID_API static void finishDumpInMemory(Dump* dump, AStatsEventList* data,
- bool lastFullDay);
+ static void saveBuffer(const std::string& path, const std::string& package, int64_t versionCode,
+ int64_t startTime, int64_t endTime, const ProfileData* data);
+
+ static Dump* createDump(int outFd, DumpType type);
+ static void addToDump(Dump* dump, const std::string& path, const std::string& package,
+ int64_t versionCode, int64_t startTime, int64_t endTime,
+ const ProfileData* data);
+ static void addToDump(Dump* dump, const std::string& path);
+ static void finishDump(Dump* dump);
+ static void finishDumpInMemory(Dump* dump, AStatsEventList* data, bool lastFullDay);
// Visible for testing
static bool parseFromFile(const std::string& path, protos::GraphicsStatsProto* output);
diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h
index 91a808df3657..36c5a8c1b3de 100644
--- a/libs/hwui/tests/common/TestUtils.h
+++ b/libs/hwui/tests/common/TestUtils.h
@@ -287,18 +287,6 @@ public:
static std::unique_ptr<uint16_t[]> asciiToUtf16(const char* str);
- class MockFunctor : public Functor {
- public:
- virtual status_t operator()(int what, void* data) {
- mLastMode = what;
- return DrawGlInfo::kStatusDone;
- }
- int getLastMode() const { return mLastMode; }
-
- private:
- int mLastMode = -1;
- };
-
static SkColor getColor(const sk_sp<SkSurface>& surface, int x, int y);
static SkRect getClipBounds(const SkCanvas* canvas);
@@ -311,30 +299,32 @@ public:
int glesDraw = 0;
};
- static void expectOnRenderThread() { EXPECT_EQ(gettid(), TestUtils::getRenderThreadTid()); }
+ static void expectOnRenderThread(const std::string_view& function = "unknown") {
+ EXPECT_EQ(gettid(), TestUtils::getRenderThreadTid()) << "Called on wrong thread: " << function;
+ }
static WebViewFunctorCallbacks createMockFunctor(RenderMode mode) {
auto callbacks = WebViewFunctorCallbacks{
.onSync =
[](int functor, void* client_data, const WebViewSyncData& data) {
- expectOnRenderThread();
+ expectOnRenderThread("onSync");
sMockFunctorCounts[functor].sync++;
},
.onContextDestroyed =
[](int functor, void* client_data) {
- expectOnRenderThread();
+ expectOnRenderThread("onContextDestroyed");
sMockFunctorCounts[functor].contextDestroyed++;
},
.onDestroyed =
[](int functor, void* client_data) {
- expectOnRenderThread();
+ expectOnRenderThread("onDestroyed");
sMockFunctorCounts[functor].destroyed++;
},
};
switch (mode) {
case RenderMode::OpenGL_ES:
callbacks.gles.draw = [](int functor, void* client_data, const DrawGlInfo& params) {
- expectOnRenderThread();
+ expectOnRenderThread("draw");
sMockFunctorCounts[functor].glesDraw++;
};
break;
diff --git a/libs/hwui/tests/common/scenes/MagnifierAnimation.cpp b/libs/hwui/tests/common/scenes/MagnifierAnimation.cpp
index f4fce277454d..edadf78db051 100644
--- a/libs/hwui/tests/common/scenes/MagnifierAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/MagnifierAnimation.cpp
@@ -56,9 +56,9 @@ public:
(float)magnifier->height(), 0, 0, (float)props.getWidth(),
(float)props.getHeight(), nullptr);
});
- canvas.insertReorderBarrier(true);
+ canvas.enableZ(true);
canvas.drawRenderNode(zoomImageView.get());
- canvas.insertReorderBarrier(false);
+ canvas.enableZ(false);
}
void doFrame(int frameNr) override {
diff --git a/libs/hwui/tests/common/scenes/RecentsAnimation.cpp b/libs/hwui/tests/common/scenes/RecentsAnimation.cpp
index 3480a0f18407..1c2507867f6e 100644
--- a/libs/hwui/tests/common/scenes/RecentsAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/RecentsAnimation.cpp
@@ -36,7 +36,7 @@ public:
int cardsize = std::min(width, height) - dp(64);
renderer.drawColor(Color::White, SkBlendMode::kSrcOver);
- renderer.insertReorderBarrier(true);
+ renderer.enableZ(true);
int x = dp(32);
for (int i = 0; i < 4; i++) {
@@ -52,7 +52,7 @@ public:
mCards.push_back(card);
}
- renderer.insertReorderBarrier(false);
+ renderer.enableZ(false);
}
void doFrame(int frameNr) override {
diff --git a/libs/hwui/tests/common/scenes/RectGridAnimation.cpp b/libs/hwui/tests/common/scenes/RectGridAnimation.cpp
index 80b5cc191089..f37bcbc3ee1b 100644
--- a/libs/hwui/tests/common/scenes/RectGridAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/RectGridAnimation.cpp
@@ -29,7 +29,7 @@ public:
sp<RenderNode> card;
void createContent(int width, int height, Canvas& canvas) override {
canvas.drawColor(0xFFFFFFFF, SkBlendMode::kSrcOver);
- canvas.insertReorderBarrier(true);
+ canvas.enableZ(true);
card = TestUtils::createNode(50, 50, 250, 250, [](RenderProperties& props, Canvas& canvas) {
canvas.drawColor(0xFFFF00FF, SkBlendMode::kSrcOver);
@@ -47,7 +47,7 @@ public:
});
canvas.drawRenderNode(card.get());
- canvas.insertReorderBarrier(false);
+ canvas.enableZ(false);
}
void doFrame(int frameNr) override {
int curFrame = frameNr % 150;
diff --git a/libs/hwui/tests/common/scenes/RoundRectClippingAnimation.cpp b/libs/hwui/tests/common/scenes/RoundRectClippingAnimation.cpp
index 314e922e9f38..163745b04ed2 100644
--- a/libs/hwui/tests/common/scenes/RoundRectClippingAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/RoundRectClippingAnimation.cpp
@@ -27,7 +27,7 @@ public:
std::vector<sp<RenderNode> > cards;
void createContent(int width, int height, Canvas& canvas) override {
canvas.drawColor(0xFFFFFFFF, SkBlendMode::kSrcOver);
- canvas.insertReorderBarrier(true);
+ canvas.enableZ(true);
int ci = 0;
for (int x = 0; x < width; x += mSpacing) {
@@ -45,7 +45,7 @@ public:
}
}
- canvas.insertReorderBarrier(false);
+ canvas.enableZ(false);
}
void doFrame(int frameNr) override {
int curFrame = frameNr % 50;
diff --git a/libs/hwui/tests/common/scenes/ShadowGrid2Animation.cpp b/libs/hwui/tests/common/scenes/ShadowGrid2Animation.cpp
index bdc991ba1890..c13e80e8c204 100644
--- a/libs/hwui/tests/common/scenes/ShadowGrid2Animation.cpp
+++ b/libs/hwui/tests/common/scenes/ShadowGrid2Animation.cpp
@@ -29,7 +29,7 @@ public:
std::vector<sp<RenderNode> > cards;
void createContent(int width, int height, Canvas& canvas) override {
canvas.drawColor(0xFFFFFFFF, SkBlendMode::kSrcOver);
- canvas.insertReorderBarrier(true);
+ canvas.enableZ(true);
for (int x = dp(8); x < (width - dp(58)); x += dp(58)) {
for (int y = dp(8); y < (height - dp(58)); y += dp(58)) {
@@ -39,7 +39,7 @@ public:
}
}
- canvas.insertReorderBarrier(false);
+ canvas.enableZ(false);
}
void doFrame(int frameNr) override {
int curFrame = frameNr % 150;
diff --git a/libs/hwui/tests/common/scenes/ShadowGridAnimation.cpp b/libs/hwui/tests/common/scenes/ShadowGridAnimation.cpp
index a12fd4d69280..772b98e32220 100644
--- a/libs/hwui/tests/common/scenes/ShadowGridAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/ShadowGridAnimation.cpp
@@ -29,7 +29,7 @@ public:
std::vector<sp<RenderNode> > cards;
void createContent(int width, int height, Canvas& canvas) override {
canvas.drawColor(0xFFFFFFFF, SkBlendMode::kSrcOver);
- canvas.insertReorderBarrier(true);
+ canvas.enableZ(true);
for (int x = dp(16); x < (width - dp(116)); x += dp(116)) {
for (int y = dp(16); y < (height - dp(116)); y += dp(116)) {
@@ -39,7 +39,7 @@ public:
}
}
- canvas.insertReorderBarrier(false);
+ canvas.enableZ(false);
}
void doFrame(int frameNr) override {
int curFrame = frameNr % 150;
diff --git a/libs/hwui/tests/common/scenes/ShadowShaderAnimation.cpp b/libs/hwui/tests/common/scenes/ShadowShaderAnimation.cpp
index 9f599100200e..0019da5fd80b 100644
--- a/libs/hwui/tests/common/scenes/ShadowShaderAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/ShadowShaderAnimation.cpp
@@ -29,7 +29,7 @@ public:
std::vector<sp<RenderNode> > cards;
void createContent(int width, int height, Canvas& canvas) override {
canvas.drawColor(0xFFFFFFFF, SkBlendMode::kSrcOver);
- canvas.insertReorderBarrier(true);
+ canvas.enableZ(true);
int outset = 50;
for (int i = 0; i < 10; i++) {
@@ -39,7 +39,7 @@ public:
cards.push_back(card);
}
- canvas.insertReorderBarrier(false);
+ canvas.enableZ(false);
}
void doFrame(int frameNr) override {
int curFrame = frameNr % 10;
diff --git a/libs/hwui/tests/common/scenes/TvApp.cpp b/libs/hwui/tests/common/scenes/TvApp.cpp
index bac887053d2f..1b0a07a98b3f 100644
--- a/libs/hwui/tests/common/scenes/TvApp.cpp
+++ b/libs/hwui/tests/common/scenes/TvApp.cpp
@@ -67,7 +67,7 @@ public:
mBg = createBitmapNode(canvas, 0xFF9C27B0, 0, 0, width, height);
canvas.drawRenderNode(mBg.get());
- canvas.insertReorderBarrier(true);
+ canvas.enableZ(true);
mSingleBitmap = mAllocator(dp(160), dp(120), kRGBA_8888_SkColorType,
[](SkBitmap& skBitmap) { skBitmap.eraseColor(0xFF0000FF); });
@@ -80,7 +80,7 @@ public:
mCards.push_back(card);
}
}
- canvas.insertReorderBarrier(false);
+ canvas.enableZ(false);
}
void doFrame(int frameNr) override {
diff --git a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
index 4ce6c32470ea..d393c693c774 100644
--- a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
+++ b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
@@ -133,14 +133,14 @@ void BM_DisplayListCanvas_basicViewGroupDraw(benchmark::State& benchState) {
int clipRestoreCount = canvas->save(SaveFlags::MatrixClip);
canvas->clipRect(1, 1, 199, 199, SkClipOp::kIntersect);
- canvas->insertReorderBarrier(true);
+ canvas->enableZ(true);
// Draw child loop
for (int i = 0; i < benchState.range(0); i++) {
canvas->drawRenderNode(child.get());
}
- canvas->insertReorderBarrier(false);
+ canvas->enableZ(false);
canvas->restoreToCount(clipRestoreCount);
delete canvas->finishRecording();
diff --git a/libs/hwui/tests/scripts/prep_generic.sh b/libs/hwui/tests/scripts/prep_generic.sh
index 223bf373c65a..89826ff69463 100755
--- a/libs/hwui/tests/scripts/prep_generic.sh
+++ b/libs/hwui/tests/scripts/prep_generic.sh
@@ -28,11 +28,17 @@
# performance between different device models.
# Fun notes for maintaining this file:
-# `expr` can deal with ints > INT32_MAX, but if compares cannot. This is why we use MHz.
-# `expr` can sometimes evaluate right-to-left. This is why we use parens.
+# $((arithmetic expressions)) can deal with ints > INT32_MAX, but if compares cannot. This is
+# why we use MHz.
+# $((arithmetic expressions)) can sometimes evaluate right-to-left. This is why we use parens.
# Everything below the initial host-check isn't bash - Android uses mksh
# mksh allows `\n` in an echo, bash doesn't
# can't use `awk`
+# can't use `sed`
+# can't use `cut` on < L
+# can't use `expr` on < L
+
+ARG_CORES=${1:-big}
CPU_TARGET_FREQ_PERCENT=50
GPU_TARGET_FREQ_PERCENT=50
@@ -43,7 +49,7 @@ if [ "`command -v getprop`" == "" ]; then
echo "Pushing $0 and running it on device..."
dest=/data/local/tmp/`basename $0`
adb push $0 ${dest}
- adb shell ${dest}
+ adb shell ${dest} $@
adb shell rm ${dest}
exit
else
@@ -56,7 +62,7 @@ if [ "`command -v getprop`" == "" ]; then
fi
# require root
-if [ "`id -u`" -ne "0" ]; then
+if [[ `id` != "uid=0"* ]]; then
echo "Not running as root, cannot lock clocks, aborting"
exit -1
fi
@@ -64,74 +70,175 @@ fi
DEVICE=`getprop ro.product.device`
MODEL=`getprop ro.product.model`
-# Find CPU max frequency, and lock big cores to an available frequency
-# that's >= $CPU_TARGET_FREQ_PERCENT% of max. Disable other cores.
+if [ "$ARG_CORES" == "big" ]; then
+ CPU_IDEAL_START_FREQ_KHZ=0
+elif [ "$ARG_CORES" == "little" ]; then
+ CPU_IDEAL_START_FREQ_KHZ=100000000 ## finding min of max freqs, so start at 100M KHz (100 GHz)
+else
+ echo "Invalid argument \$1 for ARG_CORES, should be 'big' or 'little', but was $ARG_CORES"
+ exit -1
+fi
+
+function_core_check() {
+ if [ "$ARG_CORES" == "big" ]; then
+ [ $1 -gt $2 ]
+ elif [ "$ARG_CORES" == "little" ]; then
+ [ $1 -lt $2 ]
+ else
+ echo "Invalid argument \$1 for ARG_CORES, should be 'big' or 'little', but was $ARG_CORES"
+ exit -1
+ fi
+}
+
+function_setup_go() {
+ if [ -f /d/fpsgo/common/force_onoff ]; then
+ # Disable fpsgo
+ echo 0 > /d/fpsgo/common/force_onoff
+ fpsgoState=`cat /d/fpsgo/common/force_onoff`
+ if [ "$fpsgoState" != "0" ] && [ "$fpsgoState" != "force off" ]; then
+ echo "Failed to disable fpsgo"
+ exit -1
+ fi
+ fi
+}
+
+# Find the min or max (little vs big) of CPU max frequency, and lock cores of the selected type to
+# an available frequency that's >= $CPU_TARGET_FREQ_PERCENT% of max. Disable other cores.
function_lock_cpu() {
CPU_BASE=/sys/devices/system/cpu
GOV=cpufreq/scaling_governor
+ # Options to make clock locking on go devices more sticky.
+ function_setup_go
+
# Find max CPU freq, and associated list of available freqs
- cpuMaxFreq=0
+ cpuIdealFreq=$CPU_IDEAL_START_FREQ_KHZ
cpuAvailFreqCmpr=0
cpuAvailFreq=0
enableIndices=''
disableIndices=''
cpu=0
- while [ -f ${CPU_BASE}/cpu${cpu}/online ]; do
- # enable core, so we can find its frequencies
- echo 1 > ${CPU_BASE}/cpu${cpu}/online
+ while [ -d ${CPU_BASE}/cpu${cpu}/cpufreq ]; do
+ # Try to enable core, so we can find its frequencies.
+ # Note: In cases where the online file is inaccessible, it represents a
+ # core which cannot be turned off, so we simply assume it is enabled if
+ # this command fails.
+ if [ -f "$CPU_BASE/cpu$cpu/online" ]; then
+ echo 1 > ${CPU_BASE}/cpu${cpu}/online || true
+ fi
+
+ # set userspace governor on all CPUs to ensure freq scaling is disabled
+ echo userspace > ${CPU_BASE}/cpu${cpu}/${GOV}
maxFreq=`cat ${CPU_BASE}/cpu$cpu/cpufreq/cpuinfo_max_freq`
availFreq=`cat ${CPU_BASE}/cpu$cpu/cpufreq/scaling_available_frequencies`
availFreqCmpr=${availFreq// /-}
- if [ ${maxFreq} -gt ${cpuMaxFreq} ]; then
- # new highest max freq, look for cpus with same max freq and same avail freq list
- cpuMaxFreq=${maxFreq}
+ if (function_core_check $maxFreq $cpuIdealFreq); then
+ # new min/max of max freq, look for cpus with same max freq and same avail freq list
+ cpuIdealFreq=${maxFreq}
cpuAvailFreq=${availFreq}
cpuAvailFreqCmpr=${availFreqCmpr}
- if [ -z ${disableIndices} ]; then
+ if [ -z "$disableIndices" ]; then
disableIndices="$enableIndices"
else
disableIndices="$disableIndices $enableIndices"
fi
enableIndices=${cpu}
- elif [ ${maxFreq} == ${cpuMaxFreq} ] && [ ${availFreqCmpr} == ${cpuAvailFreqCmpr} ]; then
+ elif [ ${maxFreq} == ${cpuIdealFreq} ] && [ ${availFreqCmpr} == ${cpuAvailFreqCmpr} ]; then
enableIndices="$enableIndices $cpu"
else
- disableIndices="$disableIndices $cpu"
+ if [ -z "$disableIndices" ]; then
+ disableIndices="$cpu"
+ else
+ disableIndices="$disableIndices $cpu"
+ fi
fi
+
cpu=$(($cpu + 1))
done
+ # check that some CPUs will be enabled
+ if [ -z "$enableIndices" ]; then
+ echo "Failed to find any $ARG_CORES cores to enable, aborting."
+ exit -1
+ fi
+
# Chose a frequency to lock to that's >= $CPU_TARGET_FREQ_PERCENT% of max
# (below, 100M = 1K for KHz->MHz * 100 for %)
- TARGET_FREQ_MHZ=`expr \( ${cpuMaxFreq} \* ${CPU_TARGET_FREQ_PERCENT} \) \/ 100000`
+ TARGET_FREQ_MHZ=$(( ($cpuIdealFreq * $CPU_TARGET_FREQ_PERCENT) / 100000 ))
chosenFreq=0
+ chosenFreqDiff=100000000
for freq in ${cpuAvailFreq}; do
- freqMhz=`expr ${freq} \/ 1000`
+ freqMhz=$(( ${freq} / 1000 ))
if [ ${freqMhz} -ge ${TARGET_FREQ_MHZ} ]; then
- chosenFreq=${freq}
- break
+ newChosenFreqDiff=$(( $freq - $TARGET_FREQ_MHZ ))
+ if [ $newChosenFreqDiff -lt $chosenFreqDiff ]; then
+ chosenFreq=${freq}
+ chosenFreqDiff=$(( $chosenFreq - $TARGET_FREQ_MHZ ))
+ fi
fi
done
+ # Lock wembley clocks using high-priority op code method.
+ # This block depends on the shell utility awk, which is only available on API 27+
+ if [ "$DEVICE" == "wembley" ]; then
+ # Get list of available frequencies to lock to by parsing the op-code list.
+ AVAIL_OP_FREQS=`cat /proc/cpufreq/MT_CPU_DVFS_LL/cpufreq_oppidx \
+ | awk '{print $2}' \
+ | tail -n +3 \
+ | while read line; do
+ echo "${line:1:${#line}-2}"
+ done`
+
+ # Compute the closest available frequency to the desired frequency, $chosenFreq.
+ # This assumes the op codes listen in /proc/cpufreq/MT_CPU_DVFS_LL/cpufreq_oppidx are listed
+ # in order and 0-indexed.
+ opCode=-1
+ opFreq=0
+ currOpCode=-1
+ for currOpFreq in $AVAIL_OP_FREQS; do
+ currOpCode=$((currOpCode + 1))
+
+ prevDiff=$((chosenFreq-opFreq))
+ prevDiff=`function_abs $prevDiff`
+ currDiff=$((chosenFreq-currOpFreq))
+ currDiff=`function_abs $currDiff`
+ if [ $currDiff -lt $prevDiff ]; then
+ opCode="$currOpCode"
+ opFreq="$currOpFreq"
+ fi
+ done
+
+ echo "$opCode" > /proc/ppm/policy/ut_fix_freq_idx
+ fi
+
# enable 'big' CPUs
for cpu in ${enableIndices}; do
freq=${CPU_BASE}/cpu$cpu/cpufreq
- echo 1 > ${CPU_BASE}/cpu${cpu}/online
- echo userspace > ${CPU_BASE}/cpu${cpu}/${GOV}
+ # Try to enable core, so we can find its frequencies.
+ # Note: In cases where the online file is inaccessible, it represents a
+ # core which cannot be turned off, so we simply assume it is enabled if
+ # this command fails.
+ if [ -f "$CPU_BASE/cpu$cpu/online" ]; then
+ echo 1 > ${CPU_BASE}/cpu${cpu}/online || true
+ fi
+
+ # scaling_max_freq must be set before scaling_min_freq
echo ${chosenFreq} > ${freq}/scaling_max_freq
echo ${chosenFreq} > ${freq}/scaling_min_freq
echo ${chosenFreq} > ${freq}/scaling_setspeed
+ # Give system a bit of time to propagate the change to scaling_setspeed.
+ sleep 0.1
+
# validate setting the freq worked
obsCur=`cat ${freq}/scaling_cur_freq`
obsMin=`cat ${freq}/scaling_min_freq`
obsMax=`cat ${freq}/scaling_max_freq`
- if [ obsCur -ne ${chosenFreq} ] || [ obsMin -ne ${chosenFreq} ] || [ obsMax -ne ${chosenFreq} ]; then
+ if [ "$obsCur" -ne "$chosenFreq" ] || [ "$obsMin" -ne "$chosenFreq" ] || [ "$obsMax" -ne "$chosenFreq" ]; then
echo "Failed to set CPU$cpu to $chosenFreq Hz! Aborting..."
echo "scaling_cur_freq = $obsCur"
echo "scaling_min_freq = $obsMin"
@@ -145,8 +252,20 @@ function_lock_cpu() {
echo 0 > ${CPU_BASE}/cpu${cpu}/online
done
- echo "\nLocked CPUs ${enableIndices// /,} to $chosenFreq / $maxFreq KHz"
+ echo "=================================="
+ echo "Locked CPUs ${enableIndices// /,} to $chosenFreq / $cpuIdealFreq KHz"
echo "Disabled CPUs ${disableIndices// /,}"
+ echo "=================================="
+}
+
+# Returns the absolute value of the first arg passed to this helper.
+function_abs() {
+ n=$1
+ if [ $n -lt 0 ]; then
+ echo "$((n * -1 ))"
+ else
+ echo "$n"
+ fi
}
# If we have a Qualcomm GPU, find its max frequency, and lock to
@@ -154,12 +273,12 @@ function_lock_cpu() {
function_lock_gpu_kgsl() {
if [ ! -d /sys/class/kgsl/kgsl-3d0/ ]; then
# not kgsl, abort
- echo "\nCurrently don't support locking GPU clocks of $MODEL ($DEVICE)"
+ echo "Currently don't support locking GPU clocks of $MODEL ($DEVICE)"
return -1
fi
if [ ${DEVICE} == "walleye" ] || [ ${DEVICE} == "taimen" ]; then
# Workaround crash
- echo "\nUnable to lock GPU clocks of $MODEL ($DEVICE)"
+ echo "Unable to lock GPU clocks of $MODEL ($DEVICE)"
return -1
fi
@@ -174,13 +293,13 @@ function_lock_gpu_kgsl() {
done
# (below, 100M = 1M for MHz * 100 for %)
- TARGET_FREQ_MHZ=`expr \( ${gpuMaxFreq} \* ${GPU_TARGET_FREQ_PERCENT} \) \/ 100000000`
+ TARGET_FREQ_MHZ=$(( (${gpuMaxFreq} * ${GPU_TARGET_FREQ_PERCENT}) / 100000000 ))
chosenFreq=${gpuMaxFreq}
index=0
chosenIndex=0
for freq in ${gpuAvailFreq}; do
- freqMhz=`expr ${freq} \/ 1000000`
+ freqMhz=$(( ${freq} / 1000000 ))
if [ ${freqMhz} -ge ${TARGET_FREQ_MHZ} ] && [ ${chosenFreq} -ge ${freq} ]; then
# note avail freq are generally in reverse order, so we don't break out of this loop
chosenFreq=${freq}
@@ -190,7 +309,7 @@ function_lock_gpu_kgsl() {
done
lastIndex=$(($index - 1))
- firstFreq=`echo $gpuAvailFreq | cut -d" " -f1`
+ firstFreq=`function_cut_first_from_space_seperated_list $gpuAvailFreq`
if [ ${gpuMaxFreq} != ${firstFreq} ]; then
# pwrlevel is index of desired freq among available frequencies, from highest to lowest.
@@ -226,24 +345,40 @@ function_lock_gpu_kgsl() {
echo "index = $chosenIndex"
exit -1
fi
- echo "\nLocked GPU to $chosenFreq / $gpuMaxFreq Hz"
+ echo "Locked GPU to $chosenFreq / $gpuMaxFreq Hz"
+}
+
+# cut is not available on some devices (Nexus 5 running LRX22C).
+function_cut_first_from_space_seperated_list() {
+ list=$1
+
+ for freq in $list; do
+ echo $freq
+ break
+ done
}
# kill processes that manage thermals / scaling
-stop thermal-engine
-stop perfd
-stop vendor.thermal-engine
-stop vendor.perfd
+stop thermal-engine || true
+stop perfd || true
+stop vendor.thermal-engine || true
+stop vendor.perfd || true
+setprop vendor.powerhal.init 0 || true
+setprop ctl.interface_restart android.hardware.power@1.0::IPower/default || true
function_lock_cpu
-function_lock_gpu_kgsl
+if [ "$DEVICE" -ne "wembley" ]; then
+ function_lock_gpu_kgsl
+else
+ echo "Unable to lock gpu clocks of $MODEL ($DEVICE)."
+fi
# Memory bus - hardcoded per-device for now
if [ ${DEVICE} == "marlin" ] || [ ${DEVICE} == "sailfish" ]; then
echo 13763 > /sys/class/devfreq/soc:qcom,gpubw/max_freq
else
- echo "\nUnable to lock memory bus of $MODEL ($DEVICE)."
+ echo "Unable to lock memory bus of $MODEL ($DEVICE)."
fi
-echo "\n$DEVICE clocks have been locked - to reset, reboot the device\n" \ No newline at end of file
+echo "$DEVICE clocks have been locked - to reset, reboot the device"
diff --git a/libs/hwui/tests/unit/CacheManagerTests.cpp b/libs/hwui/tests/unit/CacheManagerTests.cpp
index c83a3c88cbdd..edd3e4e4f4d4 100644
--- a/libs/hwui/tests/unit/CacheManagerTests.cpp
+++ b/libs/hwui/tests/unit/CacheManagerTests.cpp
@@ -26,7 +26,7 @@ using namespace android;
using namespace android::uirenderer;
using namespace android::uirenderer::renderthread;
-static size_t getCacheUsage(GrContext* grContext) {
+static size_t getCacheUsage(GrDirectContext* grContext) {
size_t cacheUsage;
grContext->getResourceCacheUsage(nullptr, &cacheUsage);
return cacheUsage;
@@ -35,7 +35,7 @@ static size_t getCacheUsage(GrContext* grContext) {
RENDERTHREAD_SKIA_PIPELINE_TEST(CacheManager, trimMemory) {
int32_t width = DeviceInfo::get()->getWidth();
int32_t height = DeviceInfo::get()->getHeight();
- GrContext* grContext = renderThread.getGrContext();
+ GrDirectContext* grContext = renderThread.getGrContext();
ASSERT_TRUE(grContext != nullptr);
// create pairs of offscreen render targets and images until we exceed the
@@ -47,7 +47,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(CacheManager, trimMemory) {
sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(grContext, SkBudgeted::kYes, info);
surface->getCanvas()->drawColor(SK_AlphaTRANSPARENT);
- grContext->flush();
+ grContext->flushAndSubmit();
surfaces.push_back(surface);
}
diff --git a/libs/hwui/tests/unit/CanvasContextTests.cpp b/libs/hwui/tests/unit/CanvasContextTests.cpp
index 28cff5b9b154..1771c3590e10 100644
--- a/libs/hwui/tests/unit/CanvasContextTests.cpp
+++ b/libs/hwui/tests/unit/CanvasContextTests.cpp
@@ -42,14 +42,3 @@ RENDERTHREAD_TEST(CanvasContext, create) {
canvasContext->destroy();
}
-
-RENDERTHREAD_TEST(CanvasContext, invokeFunctor) {
- TestUtils::MockFunctor functor;
- CanvasContext::invokeFunctor(renderThread, &functor);
- if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
- // we currently don't support OpenGL WebViews on the Vulkan backend
- ASSERT_EQ(functor.getLastMode(), DrawGlInfo::kModeProcessNoContext);
- } else {
- ASSERT_EQ(functor.getLastMode(), DrawGlInfo::kModeProcess);
- }
-}
diff --git a/libs/hwui/tests/unit/FatalTestCanvas.h b/libs/hwui/tests/unit/FatalTestCanvas.h
index 1723c2eb4948..76ae0853b477 100644
--- a/libs/hwui/tests/unit/FatalTestCanvas.h
+++ b/libs/hwui/tests/unit/FatalTestCanvas.h
@@ -81,21 +81,6 @@ public:
const SkPaint*) {
ADD_FAILURE() << "onDrawImageLattice not expected in this test";
}
- void onDrawBitmap(const SkBitmap&, SkScalar dx, SkScalar dy, const SkPaint*) {
- ADD_FAILURE() << "onDrawBitmap not expected in this test";
- }
- void onDrawBitmapRect(const SkBitmap&, const SkRect*, const SkRect&, const SkPaint*,
- SrcRectConstraint) {
- ADD_FAILURE() << "onDrawBitmapRect not expected in this test";
- }
- void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst,
- const SkPaint*) {
- ADD_FAILURE() << "onDrawBitmapNine not expected in this test";
- }
- void onDrawBitmapLattice(const SkBitmap&, const Lattice& lattice, const SkRect& dst,
- const SkPaint*) {
- ADD_FAILURE() << "onDrawBitmapLattice not expected in this test";
- }
void onClipRRect(const SkRRect& rrect, SkClipOp, ClipEdgeStyle) {
ADD_FAILURE() << "onClipRRect not expected in this test";
}
diff --git a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
index 3632be06c45f..7aa6be8722cf 100644
--- a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
+++ b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
@@ -108,27 +108,27 @@ protected:
TEST(RenderNodeDrawable, zReorder) {
auto parent = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
SkiaRecordingCanvas& canvas) {
- canvas.insertReorderBarrier(true);
- canvas.insertReorderBarrier(false);
+ canvas.enableZ(true);
+ canvas.enableZ(false);
drawOrderedNode(&canvas, 0, 10.0f); // in reorder=false at this point, so played inorder
drawOrderedRect(&canvas, 1);
- canvas.insertReorderBarrier(true);
+ canvas.enableZ(true);
drawOrderedNode(&canvas, 6, 2.0f);
drawOrderedRect(&canvas, 3);
drawOrderedNode(&canvas, 4, 0.0f);
drawOrderedRect(&canvas, 5);
drawOrderedNode(&canvas, 2, -2.0f);
drawOrderedNode(&canvas, 7, 2.0f);
- canvas.insertReorderBarrier(false);
+ canvas.enableZ(false);
drawOrderedRect(&canvas, 8);
drawOrderedNode(&canvas, 9, -10.0f); // in reorder=false at this point, so played inorder
- canvas.insertReorderBarrier(true); // reorder a node ahead of drawrect op
+ canvas.enableZ(true); // reorder a node ahead of drawrect op
drawOrderedRect(&canvas, 11);
drawOrderedNode(&canvas, 10, -1.0f);
- canvas.insertReorderBarrier(false);
- canvas.insertReorderBarrier(true); // test with two empty reorder sections
- canvas.insertReorderBarrier(true);
- canvas.insertReorderBarrier(false);
+ canvas.enableZ(false);
+ canvas.enableZ(true); // test with two empty reorder sections
+ canvas.enableZ(true);
+ canvas.enableZ(false);
drawOrderedRect(&canvas, 12);
});
@@ -1142,7 +1142,7 @@ TEST(ReorderBarrierDrawable, testShadowMatrix) {
0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
[](RenderProperties& props, SkiaRecordingCanvas& canvas) {
canvas.translate(TRANSLATE_X, TRANSLATE_Y);
- canvas.insertReorderBarrier(true);
+ canvas.enableZ(true);
auto node = TestUtils::createSkiaNode(
CASTER_X, CASTER_Y, CASTER_X + CASTER_WIDTH, CASTER_Y + CASTER_HEIGHT,
@@ -1152,7 +1152,7 @@ TEST(ReorderBarrierDrawable, testShadowMatrix) {
props.mutableOutline().setShouldClip(true);
});
canvas.drawRenderNode(node.get());
- canvas.insertReorderBarrier(false);
+ canvas.enableZ(false);
});
// create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection
@@ -1169,7 +1169,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaRecordingCanvas, drawVectorDrawable) {
class VectorDrawableTestCanvas : public TestCanvasBase {
public:
VectorDrawableTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {}
- void onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
+ void onDrawImageRect(const SkImage*, const SkRect* src, const SkRect& dst,
const SkPaint* paint, SrcRectConstraint constraint) override {
const int index = mDrawCounter++;
switch (index) {
diff --git a/libs/hwui/tests/unit/RenderNodeTests.cpp b/libs/hwui/tests/unit/RenderNodeTests.cpp
index 1cd9bd8ee9d9..c19e1ed6ce75 100644
--- a/libs/hwui/tests/unit/RenderNodeTests.cpp
+++ b/libs/hwui/tests/unit/RenderNodeTests.cpp
@@ -231,39 +231,41 @@ TEST(RenderNode, multiTreeValidity) {
}
TEST(RenderNode, releasedCallback) {
- class DecRefOnReleased : public GlFunctorLifecycleListener {
- public:
- explicit DecRefOnReleased(int* refcnt) : mRefCnt(refcnt) {}
- void onGlFunctorReleased(Functor* functor) override { *mRefCnt -= 1; }
-
- private:
- int* mRefCnt;
- };
-
- int refcnt = 0;
- sp<DecRefOnReleased> listener(new DecRefOnReleased(&refcnt));
- Functor noopFunctor;
+ int functor = WebViewFunctor_create(
+ nullptr, TestUtils::createMockFunctor(RenderMode::OpenGL_ES), RenderMode::OpenGL_ES);
auto node = TestUtils::createNode(0, 0, 200, 400, [&](RenderProperties& props, Canvas& canvas) {
- refcnt++;
- canvas.callDrawGLFunction(&noopFunctor, listener.get());
+ canvas.drawWebViewFunctor(functor);
+ });
+ TestUtils::runOnRenderThreadUnmanaged([&] (RenderThread&) {
+ TestUtils::syncHierarchyPropertiesAndDisplayList(node);
});
- TestUtils::syncHierarchyPropertiesAndDisplayList(node);
- EXPECT_EQ(1, refcnt);
+ auto& counts = TestUtils::countsForFunctor(functor);
+ EXPECT_EQ(1, counts.sync);
+ EXPECT_EQ(0, counts.destroyed);
TestUtils::recordNode(*node, [&](Canvas& canvas) {
- refcnt++;
- canvas.callDrawGLFunction(&noopFunctor, listener.get());
+ canvas.drawWebViewFunctor(functor);
});
- EXPECT_EQ(2, refcnt);
+ EXPECT_EQ(1, counts.sync);
+ EXPECT_EQ(0, counts.destroyed);
- TestUtils::syncHierarchyPropertiesAndDisplayList(node);
- EXPECT_EQ(1, refcnt);
+ TestUtils::runOnRenderThreadUnmanaged([&] (RenderThread&) {
+ TestUtils::syncHierarchyPropertiesAndDisplayList(node);
+ });
+ EXPECT_EQ(2, counts.sync);
+ EXPECT_EQ(0, counts.destroyed);
+
+ WebViewFunctor_release(functor);
+ EXPECT_EQ(2, counts.sync);
+ EXPECT_EQ(0, counts.destroyed);
TestUtils::recordNode(*node, [](Canvas& canvas) {});
- EXPECT_EQ(1, refcnt);
- TestUtils::syncHierarchyPropertiesAndDisplayList(node);
- EXPECT_EQ(0, refcnt);
+ TestUtils::runOnRenderThreadUnmanaged([&] (RenderThread&) {
+ TestUtils::syncHierarchyPropertiesAndDisplayList(node);
+ });
+ EXPECT_EQ(2, counts.sync);
+ EXPECT_EQ(1, counts.destroyed);
}
RENDERTHREAD_TEST(RenderNode, prepareTree_nullableDisplayList) {
diff --git a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
index d08aea668b2a..74a565439f85 100644
--- a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
+++ b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
@@ -48,7 +48,10 @@ TEST(SkiaDisplayList, reset) {
SkCanvas dummyCanvas;
RenderNodeDrawable drawable(nullptr, &dummyCanvas);
skiaDL->mChildNodes.emplace_back(nullptr, &dummyCanvas);
- GLFunctorDrawable functorDrawable(nullptr, nullptr, &dummyCanvas);
+ int functor1 = WebViewFunctor_create(
+ nullptr, TestUtils::createMockFunctor(RenderMode::OpenGL_ES), RenderMode::OpenGL_ES);
+ GLFunctorDrawable functorDrawable{functor1, &dummyCanvas};
+ WebViewFunctor_release(functor1);
skiaDL->mChildFunctors.push_back(&functorDrawable);
skiaDL->mMutableImages.push_back(nullptr);
skiaDL->appendVD(nullptr);
@@ -97,16 +100,13 @@ TEST(SkiaDisplayList, syncContexts) {
SkiaDisplayList skiaDL;
SkCanvas dummyCanvas;
- TestUtils::MockFunctor functor;
- GLFunctorDrawable functorDrawable(&functor, nullptr, &dummyCanvas);
- skiaDL.mChildFunctors.push_back(&functorDrawable);
- int functor2 = WebViewFunctor_create(
+ int functor1 = WebViewFunctor_create(
nullptr, TestUtils::createMockFunctor(RenderMode::OpenGL_ES), RenderMode::OpenGL_ES);
- auto& counts = TestUtils::countsForFunctor(functor2);
+ auto& counts = TestUtils::countsForFunctor(functor1);
skiaDL.mChildFunctors.push_back(
- skiaDL.allocateDrawable<GLFunctorDrawable>(functor2, &dummyCanvas));
- WebViewFunctor_release(functor2);
+ skiaDL.allocateDrawable<GLFunctorDrawable>(functor1, &dummyCanvas));
+ WebViewFunctor_release(functor1);
SkRect bounds = SkRect::MakeWH(200, 200);
VectorDrawableRoot vectorDrawable(new VectorDrawable::Group());
@@ -120,7 +120,6 @@ TEST(SkiaDisplayList, syncContexts) {
});
});
- EXPECT_EQ(functor.getLastMode(), DrawGlInfo::kModeSync);
EXPECT_EQ(counts.sync, 1);
EXPECT_EQ(counts.destroyed, 0);
EXPECT_EQ(vectorDrawable.mutateProperties()->getBounds(), bounds);
diff --git a/libs/hwui/utils/Blur.h b/libs/hwui/utils/Blur.h
index d6b41b83def8..6b822f01e25c 100644
--- a/libs/hwui/utils/Blur.h
+++ b/libs/hwui/utils/Blur.h
@@ -26,9 +26,9 @@ namespace uirenderer {
class Blur {
public:
// If radius > 0, return the corresponding sigma, else return 0
- ANDROID_API static float convertRadiusToSigma(float radius);
+ static float convertRadiusToSigma(float radius);
// If sigma > 0.5, return the corresponding radius, else return 0
- ANDROID_API static float convertSigmaToRadius(float sigma);
+ static float convertSigmaToRadius(float sigma);
// If the original radius was on an integer boundary then after the sigma to
// radius conversion a small rounding error may be introduced. This function
// accounts for that error and snaps to the appropriate integer boundary.
diff --git a/libs/hwui/utils/Color.cpp b/libs/hwui/utils/Color.cpp
index 71a27ced2e09..87512f0354c8 100644
--- a/libs/hwui/utils/Color.cpp
+++ b/libs/hwui/utils/Color.cpp
@@ -16,8 +16,8 @@
#include "Color.h"
-#include <utils/Log.h>
#include <ui/ColorSpace.h>
+#include <utils/Log.h>
#ifdef __ANDROID__ // Layoutlib does not support hardware buffers or native windows
#include <android/hardware_buffer.h>
@@ -26,6 +26,7 @@
#include <algorithm>
#include <cmath>
+#include <Properties.h>
namespace android {
namespace uirenderer {
@@ -72,46 +73,34 @@ SkImageInfo BufferDescriptionToImageInfo(const AHardwareBuffer_Desc& bufferDesc,
sk_sp<SkColorSpace> colorSpace) {
return createImageInfo(bufferDesc.width, bufferDesc.height, bufferDesc.format, colorSpace);
}
-#endif
-android::PixelFormat ColorTypeToPixelFormat(SkColorType colorType) {
+uint32_t ColorTypeToBufferFormat(SkColorType colorType) {
switch (colorType) {
case kRGBA_8888_SkColorType:
- return PIXEL_FORMAT_RGBA_8888;
+ return AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
case kRGBA_F16_SkColorType:
- return PIXEL_FORMAT_RGBA_FP16;
+ return AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT;
case kRGB_565_SkColorType:
- return PIXEL_FORMAT_RGB_565;
+ return AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM;
case kRGB_888x_SkColorType:
- return PIXEL_FORMAT_RGBX_8888;
+ return AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM;
case kRGBA_1010102_SkColorType:
- return PIXEL_FORMAT_RGBA_1010102;
+ return AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM;
case kARGB_4444_SkColorType:
- return PIXEL_FORMAT_RGBA_4444;
+ // Hardcoding the value from android::PixelFormat
+ static constexpr uint64_t kRGBA4444 = 7;
+ return kRGBA4444;
default:
ALOGV("Unsupported colorType: %d, return RGBA_8888 by default", (int)colorType);
- return PIXEL_FORMAT_RGBA_8888;
- }
-}
-
-SkColorType PixelFormatToColorType(android::PixelFormat format) {
- switch (format) {
- case PIXEL_FORMAT_RGBX_8888: return kRGB_888x_SkColorType;
- case PIXEL_FORMAT_RGBA_8888: return kRGBA_8888_SkColorType;
- case PIXEL_FORMAT_RGBA_FP16: return kRGBA_F16_SkColorType;
- case PIXEL_FORMAT_RGB_565: return kRGB_565_SkColorType;
- case PIXEL_FORMAT_RGBA_1010102: return kRGBA_1010102_SkColorType;
- case PIXEL_FORMAT_RGBA_4444: return kARGB_4444_SkColorType;
- default:
- ALOGV("Unsupported PixelFormat: %d, return kUnknown_SkColorType by default", format);
- return kUnknown_SkColorType;
+ return AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
}
}
+#endif
namespace {
static constexpr skcms_TransferFunction k2Dot6 = {2.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
-// Skia's SkNamedGamut::kDCIP3 is based on a white point of D65. This gamut
+// Skia's SkNamedGamut::kDisplayP3 is based on a white point of D65. This gamut
// matches the white point used by ColorSpace.Named.DCIP3.
static constexpr skcms_Matrix3x3 kDCIP3 = {{
{0.486143, 0.323835, 0.154234},
@@ -180,7 +169,7 @@ android_dataspace ColorSpaceToADataSpace(SkColorSpace* colorSpace, SkColorType c
}
}
- if (nearlyEqual(fn, SkNamedTransferFn::kSRGB) && nearlyEqual(gamut, SkNamedGamut::kDCIP3)) {
+ if (nearlyEqual(fn, SkNamedTransferFn::kSRGB) && nearlyEqual(gamut, SkNamedGamut::kDisplayP3)) {
return HAL_DATASPACE_DISPLAY_P3;
}
@@ -221,7 +210,7 @@ sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace) {
gamut = SkNamedGamut::kRec2020;
break;
case HAL_DATASPACE_STANDARD_DCI_P3:
- gamut = SkNamedGamut::kDCIP3;
+ gamut = SkNamedGamut::kDisplayP3;
break;
case HAL_DATASPACE_STANDARD_ADOBE_RGB:
gamut = SkNamedGamut::kAdobeRGB;
@@ -356,5 +345,23 @@ SkColor LabToSRGB(const Lab& lab, SkAlpha alpha) {
static_cast<uint8_t>(rgb.b * 255));
}
+skcms_TransferFunction GetPQSkTransferFunction(float sdr_white_level) {
+ if (sdr_white_level <= 0.f) {
+ sdr_white_level = Properties::defaultSdrWhitePoint;
+ }
+ // The generic PQ transfer function produces normalized luminance values i.e.
+ // the range 0-1 represents 0-10000 nits for the reference display, but we
+ // want to map 1.0 to |sdr_white_level| nits so we need to scale accordingly.
+ const double w = 10000. / sdr_white_level;
+ // Distribute scaling factor W by scaling A and B with X ^ (1/F):
+ // ((A + Bx^C) / (D + Ex^C))^F * W = ((A + Bx^C) / (D + Ex^C) * W^(1/F))^F
+ // See https://crbug.com/1058580#c32 for discussion.
+ skcms_TransferFunction fn = SkNamedTransferFn::kPQ;
+ const double ws = pow(w, 1. / fn.f);
+ fn.a = ws * fn.a;
+ fn.b = ws * fn.b;
+ return fn;
+}
+
} // namespace uirenderer
} // namespace android
diff --git a/libs/hwui/utils/Color.h b/libs/hwui/utils/Color.h
index a76f7e499c37..1654072fd264 100644
--- a/libs/hwui/utils/Color.h
+++ b/libs/hwui/utils/Color.h
@@ -16,14 +16,12 @@
#ifndef COLOR_H
#define COLOR_H
-#include <math.h>
-#include <cutils/compiler.h>
-#include <system/graphics.h>
-#include <ui/PixelFormat.h>
-
#include <SkColor.h>
#include <SkColorSpace.h>
#include <SkImageInfo.h>
+#include <cutils/compiler.h>
+#include <math.h>
+#include <system/graphics.h>
struct ANativeWindow_Buffer;
struct AHardwareBuffer_Desc;
@@ -93,15 +91,14 @@ static constexpr float EOCF_sRGB(float srgb) {
}
#ifdef __ANDROID__ // Layoutlib does not support hardware buffers or native windows
-ANDROID_API SkImageInfo ANativeWindowToImageInfo(const ANativeWindow_Buffer& buffer,
+SkImageInfo ANativeWindowToImageInfo(const ANativeWindow_Buffer& buffer,
sk_sp<SkColorSpace> colorSpace);
SkImageInfo BufferDescriptionToImageInfo(const AHardwareBuffer_Desc& bufferDesc,
sk_sp<SkColorSpace> colorSpace);
-#endif
-android::PixelFormat ColorTypeToPixelFormat(SkColorType colorType);
-ANDROID_API SkColorType PixelFormatToColorType(android::PixelFormat format);
+uint32_t ColorTypeToBufferFormat(SkColorType colorType);
+#endif
ANDROID_API sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace);
@@ -129,6 +126,7 @@ struct Lab {
Lab sRGBToLab(SkColor color);
SkColor LabToSRGB(const Lab& lab, SkAlpha alpha);
+skcms_TransferFunction GetPQSkTransferFunction(float sdr_white_level = 0.f);
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/utils/MathUtils.h b/libs/hwui/utils/MathUtils.h
index cc8d83f10d43..62bf39ca8a7a 100644
--- a/libs/hwui/utils/MathUtils.h
+++ b/libs/hwui/utils/MathUtils.h
@@ -31,7 +31,9 @@ public:
* Check for floats that are close enough to zero.
*/
inline static bool isZero(float value) {
- return (value >= -NON_ZERO_EPSILON) && (value <= NON_ZERO_EPSILON);
+ // Using fabsf is more performant as ARM computes
+ // fabsf in a single instruction.
+ return fabsf(value) <= NON_ZERO_EPSILON;
}
inline static bool isOne(float value) {
diff --git a/libs/hwui/GlFunctorLifecycleListener.h b/libs/hwui/utils/NdkUtils.cpp
index 5adc46961c8b..de6274ee5bcc 100644
--- a/libs/hwui/GlFunctorLifecycleListener.h
+++ b/libs/hwui/utils/NdkUtils.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,19 +14,19 @@
* limitations under the License.
*/
-#pragma once
-
-#include <utils/Functor.h>
-#include <utils/RefBase.h>
+#include <utils/NdkUtils.h>
namespace android {
namespace uirenderer {
-class GlFunctorLifecycleListener : public VirtualLightRefBase {
-public:
- virtual ~GlFunctorLifecycleListener() {}
- virtual void onGlFunctorReleased(Functor* functor) = 0;
-};
+UniqueAHardwareBuffer allocateAHardwareBuffer(const AHardwareBuffer_Desc& desc) {
+ AHardwareBuffer* buffer;
+ if (AHardwareBuffer_allocate(&desc, &buffer) != 0) {
+ return nullptr;
+ } else {
+ return UniqueAHardwareBuffer{buffer};
+ }
+}
} // namespace uirenderer
} // namespace android
diff --git a/libs/hwui/utils/NdkUtils.h b/libs/hwui/utils/NdkUtils.h
new file mode 100644
index 000000000000..f218eb2ff404
--- /dev/null
+++ b/libs/hwui/utils/NdkUtils.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware_buffer.h>
+
+#include <memory>
+
+namespace android {
+namespace uirenderer {
+
+// Deleter for an AHardwareBuffer, to be passed to an std::unique_ptr.
+struct AHardwareBuffer_deleter {
+ void operator()(AHardwareBuffer* ahb) const { AHardwareBuffer_release(ahb); }
+};
+
+using UniqueAHardwareBuffer = std::unique_ptr<AHardwareBuffer, AHardwareBuffer_deleter>;
+
+// Allocates a UniqueAHardwareBuffer with the provided buffer description.
+// Returns nullptr if allocation did not succeed.
+UniqueAHardwareBuffer allocateAHardwareBuffer(const AHardwareBuffer_Desc& desc);
+
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/utils/VectorDrawableUtils.h b/libs/hwui/utils/VectorDrawableUtils.h
index 4be48fb942fc..4f63959165db 100644
--- a/libs/hwui/utils/VectorDrawableUtils.h
+++ b/libs/hwui/utils/VectorDrawableUtils.h
@@ -28,10 +28,10 @@ namespace uirenderer {
class VectorDrawableUtils {
public:
- ANDROID_API static bool canMorph(const PathData& morphFrom, const PathData& morphTo);
- ANDROID_API static bool interpolatePathData(PathData* outData, const PathData& morphFrom,
+ static bool canMorph(const PathData& morphFrom, const PathData& morphTo);
+ static bool interpolatePathData(PathData* outData, const PathData& morphFrom,
const PathData& morphTo, float fraction);
- ANDROID_API static void verbsToPath(SkPath* outPath, const PathData& data);
+ static void verbsToPath(SkPath* outPath, const PathData& data);
static void interpolatePaths(PathData* outPathData, const PathData& from, const PathData& to,
float fraction);
};
diff --git a/libs/usb/tests/AccessoryChat/AndroidManifest.xml b/libs/usb/tests/AccessoryChat/AndroidManifest.xml
index 6667ebaa4d49..b93eeab11324 100644
--- a/libs/usb/tests/AccessoryChat/AndroidManifest.xml
+++ b/libs/usb/tests/AccessoryChat/AndroidManifest.xml
@@ -15,26 +15,28 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.accessorychat">
+ package="com.android.accessorychat">
- <uses-feature android:name="android.hardware.usb.accessory" />
+ <uses-feature android:name="android.hardware.usb.accessory"/>
<application android:label="Accessory Chat">
- <activity android:name="AccessoryChat" android:label="Accessory Chat">
+ <activity android:name="AccessoryChat"
+ android:label="Accessory Chat"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
- <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
+ <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"/>
</intent-filter>
<meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
- android:resource="@xml/accessory_filter" />
+ android:resource="@xml/accessory_filter"/>
</activity>
</application>
- <uses-sdk android:minSdkVersion="12" />
+ <uses-sdk android:minSdkVersion="12"/>
</manifest>