Android 12 取色引擎相关问题

1、 应用如何获取壁纸颜色?

1.1、调用getWallpaperColors获取壁纸颜色

其实WallpaperManager从很早之前就提供了getWallpaperColors接口

[WallpaperManager.java]

public @Nullable WallpaperColors getWallpaperColors(int which, int userId) {
   return sGlobals.getWallpaperColors(which, userId, mContext.getDisplayId());
}
    
WallpaperColors getWallpaperColors(int which, int userId, int displayId) {
    if (which != FLAG_LOCK && which != FLAG_SYSTEM) {
        throw new IllegalArgumentException(
                "Must request colors for exactly one kind of wallpaper");
    }

    try {
        return mService.getWallpaperColors(which, userId, displayId);
    } catch (RemoteException e) {
        // Can't get colors, connection lost.
    }
    return null;
}

1.2、注册OnColorsChangedListener接口监听壁纸颜色

1.2.1、获取整个壁纸颜色

public void addOnColorsChangedListener(@NonNull OnColorsChangedListener listener,
@NonNull Handler handler)

使用范例:
WallpaperManager wallpaperManager=(WallpaperManager) getSystemService(Context.WALLPAPER_SERVICE);
        wallpaperManager.addOnColorsChangedListener(new WallpaperManager.OnColorsChangedListener() {
            @Override
            public void onColorsChanged(WallpaperColors colors, int which) {
                
            }
        });

1.2.2、获取壁纸区域颜色(需要源码引用)

public void addOnColorsChangedListener(@NonNull LocalWallpaperColorConsumer callback,
List<RectF> regions)

==Tip: LocalWallpaperColorConsumer是hide接口,非源码编译的Apk无法引用==

使用范例:

addOnColorsChangedListener(new LocalWallpaperColorConsumer() {
    @java.lang.Override
    public void onColorsChanged(RectF area, WallpaperColors colors) {
                
    }
},handler);

1.3、使用WallpaperColors

取出的数据都封装在WallpaperColors中,可通过以下接口获取到原始数据

    //获取墙纸最具视觉代表性的颜色。“视觉上具有代表性”是指在图像中很容易被注意到,可能发生在高频率。不为空
    public @NonNull Color getPrimaryColor() {
        return mMainColors.get(0);
    }

    //获取壁纸的第二个最杰出的颜色。可以为空
    public @Nullable Color getSecondaryColor() {
        return mMainColors.size() < 2 ? null : mMainColors.get(1);
    }

    //获得壁纸的第三个最杰出的颜色。可以为空
    public @Nullable Color getTertiaryColor() {
        return mMainColors.size() < 3 ? null : mMainColors.get(2);
    }
    
    //最杰出的颜色列表,按重要性排序
    public @NonNull List<Color> getMainColors() {
        return Collections.unmodifiableList(mMainColors);
    }
    
    //得到所有提取出来的颜色,key是颜色的rgb int值 ,value是出现次数 
     public @NonNull Map<Integer, Integer> getAllColors() {
        return Collections.unmodifiableMap(mAllColors);
    }

框架中只是负责提取出原始颜色,但有些时候直接使用原始颜色,并不能达到最好的效果。

例如:PixelLauncher的插件实现颜色动态变化,除了从Wallpaper中拿到颜色,还进行了二次加工,使其更符合Material Desgin的风格,这也是符合“Monet”主题系统 中的一部分,目前是没有开源的。所以一方或三方若想使用该特性,可以按需进行选择和二次加工。

2、根据壁纸取色,能取出多少种颜色,颜色的格式和使用场景是什么?

  • 在Android 12上,内存低的机器 ,最多取出五种色值,内存高的机器,最多取出128种颜色。
if (ActivityManager.isLowRamDeviceStatic()) {
            palette = Palette
                    .from(bitmap, new VariationalKMeansQuantizer())
                    .maximumColorCount(5)
                    .resizeBitmapArea(MAX_WALLPAPER_EXTRACTION_AREA)
                    .generate();
        } else {
            palette = Palette
                    .from(bitmap, new CelebiQuantizer())
                    .maximumColorCount(128)
                    .resizeBitmapArea(MAX_WALLPAPER_EXTRACTION_AREA)
                    .generate();
        }
  • 取出的是一个WallpaperColors对象,其中包含三种主颜色,以及一个保存了所有提取出颜色的Color数组(Hide)。
  • 目前的应用场景主要是PixelLauncher、SystemUI、GBoard

3、能从动态壁纸中取色吗?

很可惜,Google并没有为动态壁纸提供默认的取色逻辑。

壁纸的取色,最终会调用到WallpaperService的onComputeColors中,但该方法是空实现,框架只是提供了最基本的获取接口而已。

所以在Android 12之前,无论是静态壁纸或是动态 壁纸,若想要其他模块能获取到壁纸颜色的话,需要壁纸提供方,在实现WallpaperService的Engine时,也一并实现onCompleteColors方法,然后在颜色变化时调用notifyColorsChanged。

[WallpaperService.java]

public void notifyColorsChanged() {
    ...

    try {
        //关键调用
        final WallpaperColors newColors = onComputeColors();
            if (mConnection != null) {
                //通知给监听壁纸颜色变化的模块
                mConnection.onWallpaperColorsChanged(newColors, mDisplay.getDisplayId());
            } else {
                 Log.w(TAG, "Can't notify system because wallpaper connection "
                        + "was not established.");
            }
            ...
        } catch (RemoteException e) {
            Log.w(TAG, "Can't notify system because wallpaper connection was lost.", e);
        }
}

//重写该方法
public @Nullable WallpaperColors onComputeColors() {
    return null;
}

如图:

特性 < Android 12 Android 12
静态壁纸 没有默认实现 提供了默认实现,可以根据区域取色
动态壁纸 空实现 空实现

4、壁纸取色失败会使用默认颜色吗?

壁纸其实是通过Palette接口进行颜色提取的,基本上都能取到至少一种颜色。当真的取出失败或取出的颜色如果不符合期望,需要采用另外一套默认颜色,这是由各个各个业务去处理的,比如Launcher中的LauncherAppWidgetHostView,重写了setColorResources方法

@Override
public void setColorResources(@Nullable SparseIntArray colors) {
    if (colors == null) {
        //关键点1,提取不到颜色,会重置插件的颜色
        resetColorResources();
    } else {
        //关键点2,设置插件的颜色
        super.setColorResources(colors);
    }
}  

5、Widget 取色的整体流程是怎样?

具体流程见下图:


时序.png

PixelLauncher是通过LocalWallpaperColorsExtractor的实现类进行颜色提取,该类继承于LocalColorExtractor,该类存在于Launcher3中,是空实现。可以看出,Google专门将Monet算法部分折分隐藏,只公开框架部分。

而LocalWallpaperColorsExtractor是通过调用WallpaperManager.addOnColorsChangedListener接口,获取onColorsChanged(RectF rectF, WallpaperColors wallpaperColors)中的返回信息,然后再对WallpaperColors中的颜色信息进行二次加工处理。

6、Widget 能使用的颜色数量和范围

  • Widget能使用的色值数量没有限制,从android.R.color.system_neutrall_0(#FFFFFF) 到android.R.color.system_accent3_1000(#000000)都是合法范围。

7、为什么现有第三方 Launcher 即使在 Android 12 上,Widget 的取色也会无效,而 Pixel Launcher 可以。

  • 第三方 Launcher 代码中虽然已经有调用AppWidgetHostView.setColorResources,但是因为其提取颜色的LocalColorExtractor是空实现,所以没有实际效果。而Pixel Launcher 自己写了一个LocalWallpaperColorsExtractor去继承LocalColorExtractor。详见以下代码:
    [LocalColorExtractor.java]
    public static LocalColorExtractor newInstance(Context context) {
        return Overrides.getObject(WallpaperColors.class, context.getApplicationContext(),
                R.string.local_colors_extraction_class);
    }
    
    
    local_colors_extraction_class 该值定义在PixelLauncher中

    <string name="local_colors_extraction_class">com.google.android.apps.nexuslauncher.widget.LocalWallpaperColorsExtractor</string>

8、是否可以固定设置一套或者几套颜色,去overlay 壁纸的取色?

可以,Android 12已经在secure表中预定义了theme_customization_overlay_packages字段,在其中配置了是否要根据主屏幕变色还是预置颜色,然后进行资源Overlay的。

Android 原生设置入口

image.png

theme_customization_overlay_packages字段含义

字段 含义 取值范围
android.theme.customization.color_index 选择颜色索引 0~n
android.theme.customization.system_palette 中立色 color
android.theme.customization.accent_color 强调色 color
android.theme.customization.color_source 采用跟随壁纸颜色还是基本颜色 present \ home_wallpaper \ lock_wallpaper
android.theme.customization.color_both" 区分当前壁纸设置类型 1 锁屏和主屏幕, 0 只设置其中一项

我们可以直接使用或借鉴这套逻辑,预置几套色值,并设置为使用基本颜色。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,013评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,205评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,370评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,168评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,153评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,954评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,271评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,916评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,382评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,877评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,989评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,624评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,209评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,199评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,418评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,401评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,700评论 2 345

推荐阅读更多精彩内容