blob: 9f9c5e656e00a5c47f7db174e676a7e2a1c40a45 [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package android.systemui.cts;
import static androidx.test.InstrumentationRegistry.getInstrumentation;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Rect;
import android.util.Log;
import android.view.DisplayCutout;
import android.view.WindowInsets;
import androidx.test.InstrumentationRegistry;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Locale;
public class LightBarTestBase {
private static final String TAG = "LightBarTestBase";
public static final Path DUMP_PATH = FileSystems.getDefault()
.getPath("/sdcard/LightBarTestBase/");
public static final int WAIT_TIME = 2000;
private static final int COLOR_DIFF_THESHOLDS = 2;
private ArrayList<Rect> mCutouts;
protected Bitmap takeStatusBarScreenshot(LightBarBaseActivity activity) {
Bitmap fullBitmap = getInstrumentation().getUiAutomation().takeScreenshot();
return Bitmap.createBitmap(fullBitmap, activity.getLeft(), 0,
activity.getWidth(), activity.getTop());
}
protected Bitmap takeNavigationBarScreenshot(LightBarBaseActivity activity) {
Bitmap fullBitmap = getInstrumentation().getUiAutomation().takeScreenshot();
return Bitmap.createBitmap(fullBitmap, activity.getLeft(), activity.getBottom(),
activity.getRight(), fullBitmap.getHeight() - activity.getBottom());
}
protected void dumpBitmap(Bitmap bitmap, String name) {
File dumpDir = DUMP_PATH.toFile();
if (!dumpDir.exists()) {
dumpDir.mkdirs();
}
Path filePath = DUMP_PATH.resolve(name + ".png");
Log.e(TAG, "Dumping failed bitmap to " + filePath);
FileOutputStream fileStream = null;
try {
fileStream = new FileOutputStream(filePath.toFile());
bitmap.compress(Bitmap.CompressFormat.PNG, 85, fileStream);
fileStream.flush();
} catch (Exception e) {
Log.e(TAG, "Dumping bitmap failed.", e);
} finally {
if (fileStream != null) {
try {
fileStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
protected void checkNavigationBarDivider(LightBarBaseActivity activity, int dividerColor,
int backgroundColor, String methodName) {
final Bitmap bitmap = takeNavigationBarScreenshot(activity);
int[] pixels = new int[bitmap.getHeight() * bitmap.getWidth()];
bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
loadCutout(activity);
int backgroundColorPixelCount = 0;
int shiftY = activity.getBottom();
for (int i = 0; i < pixels.length; i++) {
int x = i % bitmap.getWidth();
int y = i / bitmap.getWidth();
if (isColorSame(pixels[i], backgroundColor) || isInsideCutout(x, shiftY + y)) {
backgroundColorPixelCount++;
}
}
assumeNavigationBarChangesColor(backgroundColorPixelCount, pixels.length);
int diffCount = 0;
for (int col = 0; col < bitmap.getWidth(); col++) {
if (isInsideCutout(col, shiftY)) {
continue;
}
if (!isColorSame(dividerColor, pixels[col])) {
diffCount++;
}
}
boolean success = false;
try {
assertLessThan(String.format(Locale.ENGLISH,
"There are invalid color pixels. expected= 0x%08x", dividerColor),
0.3f, (float) diffCount / (float)bitmap.getWidth(),
"Is the divider colored according to android:navigationBarDividerColor "
+ " in the theme?");
success = true;
} finally {
if (!success) {
dumpBitmap(bitmap, methodName);
}
}
}
private static boolean isColorSame(int c1, int c2) {
return Math.abs(Color.alpha(c1) - Color.alpha(c2)) < COLOR_DIFF_THESHOLDS
&& Math.abs(Color.red(c1) - Color.red(c2)) < COLOR_DIFF_THESHOLDS
&& Math.abs(Color.green(c1) - Color.green(c2)) < COLOR_DIFF_THESHOLDS
&& Math.abs(Color.blue(c1) - Color.blue(c2)) < COLOR_DIFF_THESHOLDS;
}
protected void assumeNavigationBarChangesColor(int backgroundColorPixelCount, int totalPixel) {
assumeTrue("Not enough background pixels. The navigation bar may not be able to change "
+ "color.", backgroundColorPixelCount > 0.3f * totalPixel);
}
protected ArrayList loadCutout(LightBarBaseActivity activity) {
mCutouts = new ArrayList<>();
InstrumentationRegistry.getInstrumentation().runOnMainSync(()-> {
WindowInsets windowInsets = activity.getRootWindowInsets();
DisplayCutout displayCutout = windowInsets.getDisplayCutout();
if (displayCutout != null) {
mCutouts.addAll(displayCutout.getBoundingRects());
}
});
return mCutouts;
}
protected boolean isInsideCutout(int x, int y) {
for (Rect cutout : mCutouts) {
if (cutout.contains(x, y)) {
return true;
}
}
return false;
}
protected void assertMoreThan(String what, float expected, float actual, String hint) {
if (!(actual > expected)) {
fail(what + ": expected more than " + expected * 100 + "%, but only got " + actual * 100
+ "%; " + hint);
}
}
protected void assertLessThan(String what, float expected, float actual, String hint) {
if (!(actual < expected)) {
fail(what + ": expected less than " + expected * 100 + "%, but got " + actual * 100
+ "%; " + hint);
}
}
}