blob: 14282bfbd24e86a15cd889b5cfe4ac6894ef1f10 [file] [log] [blame]
Felka Chang489cf262019-12-26 13:36:23 +08001/*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.view;
18
19import android.content.Context;
20import android.graphics.Matrix;
21import android.graphics.Path;
22import android.graphics.Rect;
23import android.graphics.RectF;
24import android.graphics.Region;
25import android.perftests.utils.BenchmarkState;
26import android.perftests.utils.PerfStatusReporter;
27import android.text.TextUtils;
28import android.util.DisplayMetrics;
29import android.util.Log;
30import android.util.PathParser;
31
32import androidx.test.filters.LargeTest;
33import androidx.test.platform.app.InstrumentationRegistry;
34import androidx.test.runner.AndroidJUnit4;
35
36import org.junit.Before;
37import org.junit.Rule;
38import org.junit.Test;
39import org.junit.runner.RunWith;
40
41@RunWith(AndroidJUnit4.class)
42@LargeTest
43public class CutoutSpecificationBenchmark {
44 private static final String TAG = "CutoutSpecificationBenchmark";
45
46 private static final String BOTTOM_MARKER = "@bottom";
47 private static final String DP_MARKER = "@dp";
48 private static final String RIGHT_MARKER = "@right";
49 private static final String LEFT_MARKER = "@left";
50
51 private static final String DOUBLE_CUTOUT_SPEC = "M 0,0\n"
52 + "L -72, 0\n"
53 + "L -69.9940446283, 20.0595537175\n"
54 + "C -69.1582133885, 28.4178661152 -65.2, 32.0 -56.8, 32.0\n"
55 + "L 56.8, 32.0\n"
56 + "C 65.2, 32.0 69.1582133885, 28.4178661152 69.9940446283, 20.0595537175\n"
57 + "L 72, 0\n"
58 + "Z\n"
59 + "@bottom\n"
60 + "M 0,0\n"
61 + "L -72, 0\n"
62 + "L -69.9940446283, -20.0595537175\n"
63 + "C -69.1582133885, -28.4178661152 -65.2, -32.0 -56.8, -32.0\n"
64 + "L 56.8, -32.0\n"
65 + "C 65.2, -32.0 69.1582133885, -28.4178661152 69.9940446283, -20.0595537175\n"
66 + "L 72, 0\n"
67 + "Z\n"
68 + "@dp";
69 @Rule
70 public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
71
72 private Context mContext;
73 private DisplayMetrics mDisplayMetrics;
74
75 /**
76 * Setup the necessary member field used by test methods.
77 */
78 @Before
79 public void setUp() {
80 mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
81
82 mDisplayMetrics = new DisplayMetrics();
83 mContext.getDisplay().getRealMetrics(mDisplayMetrics);
84 }
85
86
87 private static void toRectAndAddToRegion(Path p, Region inoutRegion, Rect inoutRect) {
88 final RectF rectF = new RectF();
89 p.computeBounds(rectF, false /* unused */);
90 rectF.round(inoutRect);
91 inoutRegion.op(inoutRect, Region.Op.UNION);
92 }
93
94 private static void oldMethodParsingSpec(String spec, int displayWidth, int displayHeight,
95 float density) {
96 Path p = null;
97 Rect boundTop = null;
98 Rect boundBottom = null;
99 Rect safeInset = new Rect();
100 String bottomSpec = null;
101 if (!TextUtils.isEmpty(spec)) {
102 spec = spec.trim();
103 final float offsetX;
104 if (spec.endsWith(RIGHT_MARKER)) {
105 offsetX = displayWidth;
106 spec = spec.substring(0, spec.length() - RIGHT_MARKER.length()).trim();
107 } else if (spec.endsWith(LEFT_MARKER)) {
108 offsetX = 0;
109 spec = spec.substring(0, spec.length() - LEFT_MARKER.length()).trim();
110 } else {
111 offsetX = displayWidth / 2f;
112 }
113 final boolean inDp = spec.endsWith(DP_MARKER);
114 if (inDp) {
115 spec = spec.substring(0, spec.length() - DP_MARKER.length());
116 }
117
118 if (spec.contains(BOTTOM_MARKER)) {
119 String[] splits = spec.split(BOTTOM_MARKER, 2);
120 spec = splits[0].trim();
121 bottomSpec = splits[1].trim();
122 }
123
124 final Matrix m = new Matrix();
125 final Region r = Region.obtain();
126 if (!spec.isEmpty()) {
127 try {
128 p = PathParser.createPathFromPathData(spec);
129 } catch (Throwable e) {
130 Log.wtf(TAG, "Could not inflate cutout: ", e);
131 }
132
133 if (p != null) {
134 if (inDp) {
135 m.postScale(density, density);
136 }
137 m.postTranslate(offsetX, 0);
138 p.transform(m);
139
140 boundTop = new Rect();
141 toRectAndAddToRegion(p, r, boundTop);
142 safeInset.top = boundTop.bottom;
143 }
144 }
145
146 if (bottomSpec != null) {
147 int bottomInset = 0;
148 Path bottomPath = null;
149 try {
150 bottomPath = PathParser.createPathFromPathData(bottomSpec);
151 } catch (Throwable e) {
152 Log.wtf(TAG, "Could not inflate bottom cutout: ", e);
153 }
154
155 if (bottomPath != null) {
156 // Keep top transform
157 m.postTranslate(0, displayHeight);
158 bottomPath.transform(m);
159 p.addPath(bottomPath);
160 boundBottom = new Rect();
161 toRectAndAddToRegion(bottomPath, r, boundBottom);
162 bottomInset = displayHeight - boundBottom.top;
163 }
164 safeInset.bottom = bottomInset;
165 }
166 }
167 }
168
169 @Test
170 public void parseByOldMethodForDoubleCutout() {
171 final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
172 while (state.keepRunning()) {
173 oldMethodParsingSpec(DOUBLE_CUTOUT_SPEC, mDisplayMetrics.widthPixels,
174 mDisplayMetrics.heightPixels, mDisplayMetrics.density);
175 }
176 }
177
178 @Test
179 public void parseByNewMethodForDoubleCutout() {
180 final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
181 while (state.keepRunning()) {
182 new CutoutSpecification.Parser(mDisplayMetrics.density,
183 mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels)
184 .parse(DOUBLE_CUTOUT_SPEC);
185 }
186 }
187
188 @Test
189 public void parseLongEdgeCutout() {
190 final String spec = "M 0,0\n"
191 + "H 48\n"
192 + "V 48\n"
193 + "H -48\n"
194 + "Z\n"
195 + "@left\n"
196 + "@center_vertical\n"
197 + "M 0,0\n"
198 + "H 48\n"
199 + "V 48\n"
200 + "H -48\n"
201 + "Z\n"
202 + "@left\n"
203 + "@center_vertical\n"
204 + "M 0,0\n"
205 + "H -48\n"
206 + "V 48\n"
207 + "H 48\n"
208 + "Z\n"
209 + "@right\n"
210 + "@dp";
211
212 final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
213 while (state.keepRunning()) {
214 new CutoutSpecification.Parser(mDisplayMetrics.density,
215 mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels).parse(spec);
216 }
217 }
218
219 @Test
220 public void parseShortEdgeCutout() {
221 final String spec = "M 0,0\n"
222 + "H 48\n"
223 + "V 48\n"
224 + "H -48\n"
225 + "Z\n"
226 + "@bottom\n"
227 + "M 0,0\n"
228 + "H 48\n"
229 + "V -48\n"
230 + "H -48\n"
231 + "Z\n"
232 + "@dp";
233
234 final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
235 while (state.keepRunning()) {
236 new CutoutSpecification.Parser(mDisplayMetrics.density,
237 mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels).parse(spec);
238 }
239 }
240}