Android 13 取色引擎詳解

1黔衡、 應(yīng)用如何獲取壁紙顏色届氢?

1.1缠借、調(diào)用getWallpaperColors獲取壁紙顏色

其實WallpaperManager從很早之前就提供了getWallpaperColors接口
/frameworks/base/core/java/android/app/WallpaperManager.java

...
    @UnsupportedAppUsage
    public @Nullable WallpaperColors getWallpaperColors(int which, int userId) {
        StrictMode.assertUiContext(mContext, "getWallpaperColors");
        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究履、注冊O(shè)nColorsChangedListener接口監(jiān)聽壁紙顏色

1.2.1川慌、獲取整個壁紙顏色

/frameworks/base/core/java/android/app/WallpaperManager.java

...
    public void addOnColorsChangedListener(@NonNull OnColorsChangedListener listener,
            @NonNull Handler handler) {
        addOnColorsChangedListener(listener, handler, mContext.getUserId());
    }
...

使用范例:

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

1.2.2亡笑、獲取壁紙區(qū)域顏色(需要源碼引用)
/frameworks/base/core/java/android/app/WallpaperManager.java

...
    /**
     * @hide
     */
    public void addOnColorsChangedListener(@NonNull LocalWallpaperColorConsumer callback,
            List<RectF> regions) throws IllegalArgumentException {
        for (RectF region : regions) {
            if (!LOCAL_COLOR_BOUNDS.contains(region)) {
                throw new IllegalArgumentException("Regions must be within bounds "
                        + LOCAL_COLOR_BOUNDS);
            }
        }
        sGlobals.addOnColorsChangedListener(callback, regions, FLAG_SYSTEM,
                                                 mContext.getUserId(), mContext.getDisplayId());
    }
...

==Tip: LocalWallpaperColorConsumer是hide接口侣夷,非源碼編譯的Apk無法引用==

使用范例:

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

1.3、使用WallpaperColors

取出的數(shù)據(jù)都封裝在WallpaperColors中仑乌,可通過以下接口獲取到原始數(shù)據(jù)
/frameworks/base/core/java/android/app/WallpaperColors.java

    //獲取墻紙最具視覺代表性的顏色百拓。“視覺上具有代表性”是指在圖像中很容易被注意到晰甚,可能發(fā)生在高頻率衙传。不為空
    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是出現(xiàn)次數(shù) 
     public @NonNull Map<Integer, Integer> getAllColors() {
        return Collections.unmodifiableMap(mAllColors);
    }

框架中只是負責(zé)提取出原始顏色刻像,但有些時候直接使用原始顏色,并不能達到最好的效果并闲。

例如:PixelLauncher的插件實現(xiàn)顏色動態(tài)變化细睡,除了從Wallpaper中拿到顏色,還進行了二次加工帝火,使其更符合Material Desgin的風(fēng)格溜徙,這也是符合“Monet”主題系統(tǒng) 中的一部分,目前是沒有開源的购公。所以一方或三方若想使用該特性萌京,可以按需進行選擇和二次加工。

2知残、根據(jù)壁紙取色,能取出多少種顏色神凑,顏色的格式和使用場景是什么?

在Android 13上坡慌,內(nèi)存低的機器 ,最多取出五種色值岖寞,內(nèi)存高的機器淑履,最多取出128種顏色勉耀。
/frameworks/base/core/java/android/app/WallpaperColors.java

...
    public static WallpaperColors fromBitmap(@NonNull Bitmap bitmap,
            @FloatRange (from = 0f, to = 1f) float dimAmount) {
...
        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數(shù)組(Hide)吗讶。
  • 目前的應(yīng)用場景主要是PixelLauncher、SystemUI恋捆、GBoard

3关翎、能從動態(tài)壁紙中取色嗎?

很可惜鸠信,Google并沒有為動態(tài)壁紙?zhí)峁┠J的取色邏輯。

壁紙的取色论寨,最終會調(diào)用到WallpaperService的onComputeColors中星立,但該方法是空實現(xiàn),框架只是提供了最基本的獲取接口而已葬凳。

所以在Android 13之前绰垂,無論是靜態(tài)壁紙或是動態(tài) 壁紙,若想要其他模塊能獲取到壁紙顏色的話火焰,需要壁紙?zhí)峁┓骄⒆埃趯崿F(xiàn)WallpaperService的Engine時,也一并實現(xiàn)onCompleteColors方法,然后在顏色變化時調(diào)用notifyColorsChanged占业。
/frameworks/base/core/java/android/service/wallpaper/WallpaperService.java

...
public void notifyColorsChanged() {
    ...

    try {
        //關(guān)鍵調(diào)用
        final WallpaperColors newColors = onComputeColors();
            if (mConnection != null) {
                //通知給監(jiān)聽壁紙顏色變化的模塊
                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 13 Android 13
靜態(tài)壁紙 沒有默認實現(xiàn) 提供了默認實現(xiàn)绒怨,可以根據(jù)區(qū)域取色
動態(tài)壁紙 空實現(xiàn) 空實現(xiàn)

4、壁紙取色失敗會使用默認顏色嗎谦疾?

壁紙其實是通過Palette接口進行顏色提取的南蹂,基本上都能取到至少一種顏色。當(dāng)真的取出失敗或取出的顏色如果不符合期望念恍,需要采用另外一套默認顏色六剥,這是由各個各個業(yè)務(wù)去處理的,比如Launcher中的LauncherAppWidgetHostView峰伙,重寫了setColorResources方法
/packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java

...
@Override
public void setColorResources(@Nullable SparseIntArray colors) {
    if (colors == null) {
        //關(guān)鍵點1疗疟,提取不到顏色,會重置插件的顏色
        resetColorResources();
    } else {
        //關(guān)鍵點2瞳氓,設(shè)置插件的顏色
        super.setColorResources(colors);
    }
}
...

5策彤、Widget 取色的整體流程是怎樣?

具體流程見下圖:

PixelLauncher是通過LocalWallpaperColorsExtractor的實現(xiàn)類進行顏色提取顿膨,該類繼承于LocalColorExtractor锅锨,該類存在于Launcher3中,是空實現(xiàn)恋沃”馗悖可以看出,Google專門將Monet算法部分折分隱藏囊咏,只公開框架部分恕洲。

而LocalWallpaperColorsExtractor是通過調(diào)用WallpaperManager.addOnColorsChangedListener接口,獲取onColorsChanged(RectF rectF, WallpaperColors wallpaperColors)中的返回信息梅割,然后再對WallpaperColors中的顏色信息進行二次加工處理霜第。

6、Widget 能使用的顏色數(shù)量和范圍

Widget能使用的色值數(shù)量沒有限制户辞,從android.R.color.system_neutrall_0(#FFFFFF) 到android.R.color.system_accent3_1000(#000000)都是合法范圍泌类。

7、為什么現(xiàn)有第三方Launcher即使在Android13上底燎,Widget的取色也會無效刃榨,而 Pixel Launcher可以。

第三方 Launcher 代碼中雖然已經(jīng)有調(diào)用AppWidgetHostView.setColorResources双仍,但是因為其提取顏色的LocalColorExtractor是空實現(xiàn)枢希,所以沒有實際效果。而Pixel Launcher 自己寫了一個LocalWallpaperColorsExtractor去繼承LocalColorExtractor朱沃。詳見以下代碼:

/packages/apps/Launcher3/src/com/android/launcher3/widget/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苞轿、是否可以固定設(shè)置一套或者幾套顏色茅诱,去overlay 壁紙的取色?

可以搬卒,Android 13已經(jīng)在secure表中預(yù)定義了theme_customization_overlay_packages字段瑟俭,在其中配置了是否要根據(jù)主屏幕變色還是預(yù)置顏色,然后進行資源Overlay的秀睛。
Android 原生設(shè)置入口


theme_customization_overlay_packages字段含義

字段 含義 取值范圍
android.theme.customization.color_index 選擇顏色索引 0~n
android.theme.customization.system_palette 中立色 color
android.theme.customization.accent_color 強調(diào)色 color
android.theme.customization.color_source 采用跟隨壁紙顏色還是基本顏色 present \ home_wallpaper \ lock_wallpaper
android.theme.customization.color_both" 區(qū)分當(dāng)前壁紙設(shè)置類型 1 鎖屏和主屏幕尔当, 0 只設(shè)置其中一項

我們可以直接使用或借鑒這套邏輯,預(yù)置幾套色值蹂安,并設(shè)置為使用基本顏色椭迎。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市田盈,隨后出現(xiàn)的幾起案子畜号,更是在濱河造成了極大的恐慌,老刑警劉巖允瞧,帶你破解...
    沈念sama閱讀 218,386評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件简软,死亡現(xiàn)場離奇詭異,居然都是意外死亡述暂,警方通過查閱死者的電腦和手機痹升,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評論 3 394
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來畦韭,“玉大人疼蛾,你說我怎么就攤上這事∫张洌” “怎么了察郁?”我有些...
    開封第一講書人閱讀 164,704評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長转唉。 經(jīng)常有香客問我皮钠,道長,這世上最難降的妖魔是什么赠法? 我笑而不...
    開封第一講書人閱讀 58,702評論 1 294
  • 正文 為了忘掉前任麦轰,我火速辦了婚禮,結(jié)果婚禮上砖织,老公的妹妹穿的比我還像新娘原朝。我一直安慰自己,他們只是感情好镶苞,可當(dāng)我...
    茶點故事閱讀 67,716評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著鞠评,像睡著了一般茂蚓。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,573評論 1 305
  • 那天聋涨,我揣著相機與錄音晾浴,去河邊找鬼。 笑死牍白,一個胖子當(dāng)著我的面吹牛脊凰,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播茂腥,決...
    沈念sama閱讀 40,314評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼狸涌,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了最岗?” 一聲冷哼從身側(cè)響起帕胆,我...
    開封第一講書人閱讀 39,230評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎般渡,沒想到半個月后懒豹,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,680評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡驯用,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,873評論 3 336
  • 正文 我和宋清朗相戀三年脸秽,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蝴乔。...
    茶點故事閱讀 39,991評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡记餐,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出淘这,到底是詐尸還是另有隱情剥扣,我是刑警寧澤,帶...
    沈念sama閱讀 35,706評論 5 346
  • 正文 年R本政府宣布铝穷,位于F島的核電站钠怯,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏曙聂。R本人自食惡果不足惜晦炊,卻給世界環(huán)境...
    茶點故事閱讀 41,329評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望宁脊。 院中可真熱鬧断国,春花似錦、人聲如沸榆苞。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽坐漏。三九已至薄疚,卻和暖如春碧信,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背街夭。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評論 1 270
  • 我被黑心中介騙來泰國打工砰碴, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人板丽。 一個月前我還...
    沈念sama閱讀 48,158評論 3 370
  • 正文 我出身青樓呈枉,卻偏偏與公主長得像,于是被迫代替她去往敵國和親埃碱。 傳聞我的和親對象是個殘疾皇子猖辫,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,941評論 2 355

推薦閱讀更多精彩內(nèi)容