Android 深色模式适配原理分析( 六 )

< lab.L) {// 若取反后亮度变暗 , 则替换原来亮度lab.L = invertedL;// 重新转换为sRGB模式return LabToSRGB(lab, SkColorGetA(color));} else {return color;}}从代码中可以看出 , 深色模式应用之后 , 通过对sRGB色彩空间转换Lab色彩空间 , 并对表示亮度的维度L进行取反 , 并判断取反后前景色是不是更亮 , 后景色是不是更暗 , 若是的话就替换为原来的L , 并再重新转换为sRGB色彩空间 , 从而实现反色的效果 。
我们再来看对图片的强制深色模式处理:
// Bitmap绘制颜色模式转换bool transformPaint(ColorTransform transform, SkPaint* paint, BitmapPalette palette) {// 考虑加上filter之后图片的明暗palette = filterPalette(paint, palette);bool shouldInvert = false;if (palette == BitmapPalette::Light}if (palette == BitmapPalette::Dark}if (shouldInvert) {SkHighContrastConfig config;// 设置skia反转亮度的filterconfig.fInvertStyle = SkHighContrastConfig::InvertStyle::kInvertLightness;paint->setColorFilter(SkHighContrastFilter::Make(config)->makeComposed(paint->refColorFilter()));}return shouldInvert;}// 获取paint filter的palette值 , 若没有filter直接返回原来的palettestatic BitmapPalette filterPalette(const SkPaint* paint, BitmapPalette palette) {// 如果没有filter color返回原来的paletteif (palette == BitmapPalette::Unknown || !paint || !paint->getColorFilter()) {return palette;}SkColor color = palette == BitmapPalette::Light ? SK_ColorWHITE : SK_ColorBLACK;// 获取filter color , 并根据palette的明暗再叠加一层白色或者黑色color = paint->getColorFilter()->filterColor(color);// 根据将颜色转换为HSV空间 , 并返回是图片的亮度是亮还是暗return paletteForColorHSV(color);}从代码中可以看出 , 对于Bitmap类型的绘制 , 先判断原来绘制Bitmap的明暗度 , 如果原来绘制的图像较为明亮但是需要变暗 , 或者原来绘制的图像较为暗需要变明亮 , 则设置一个明亮度转换的filter到画笔paint中 。
至此 , 对于主题级别的强制深色转换原理已经非常清晰 。 总结一下 , 就是需要对前景色变亮和背景色变暗 , 然后对于非Bitmap类型明暗变化采用的是将色值转换为Lab颜色空间进行明亮度转换 , 对于Bitmap类型的明暗变化采取设置亮度转换的filter进行 。
2. View
无论是设置View的xml的android:forceDarkAllowed属性 , 还是调用View.setForceDarkAllowed()最后还是调用到frameworks/base/core/java/android/view/View.java的mRenderNode.setForceDarkAllowed()方法 。
frameworks/base/graphics/java/android/graphics/RenderNode.java
public boolean setForceDarkAllowed(boolean allow) {return nSetAllowForceDark(mNativeRenderNode, allow);}nSetAllowForceDark通过JNI调用到android_view_RenderNode_setAllowForceDarkNavtive方法中 。
frameworks/base/libs/hwui/jni/android_graphics_RenderNode.cpp
static const JNINativeMethod gMethods[] = {// ...{ "nSetAllowForceDark","(JZ)Z", (void*) android_view_RenderNode_setAllowForceDark },// ...};static jboolean android_view_RenderNode_setAllowForceDark(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr, jboolean allow) {return SET_AND_DIRTY(setAllowForceDark, allow, RenderNode::GENERIC);}#define SET_AND_DIRTY(prop, val, dirtyFlag) \(reinterpret_cast(renderNodePtr)->mutateStagingProperties().prop(val) \? (reinterpret_cast