android P都已经出来好久了,今天在使用Android P过程中发现在Dislpay下面有一个主题设置(Device theme)
如下所示
可以看出一个有3个选项,通过使用后发现,他运行用户设置手机主题,跟app主题不一样,这里的主题设置可以供系统以及所有应用查询.系统主题一共有暗和亮两张状态.上面设置中3个选项代表的意义如下:
设置亮主题:
这样看效果还是挺明显的.通过源码发现,目前系统上launche和SystemUI监听了系统主题的状态,然后显示系统的主题,其他app如果需要根据系统当前主题,也需要实时监听主题变化,
个人app要监听系统主题,直接使用WallpaperManager,addOnColorsChangedListener方法,通过listener回调
实现步奏如下:
if (wallpaperManager == null) {
wallpaperManager = WallpaperManager.getInstance(context.getApplicationContext());
}
调用WallpaperManager的单例,实际上就是getSystemService
public static WallpaperManager getInstance(Context context) {
return (WallpaperManager)context.getSystemService(
Context.WALLPAPER_SERVICE);
}
这个回调方法会在主题切换中触发,下面是触发后调用的方法
WallpaperManager.OnColorsChangedListener onColorsChangedListener = new WallpaperManager.OnColorsChangedListener(){
@Override
public void onColorsChanged(WallpaperColors colors, int which) {//1
if (WallpaperManager.FLAG_SYSTEM == which) {//2
updateTheme(colors);
}
}
};
wallpaperManager.addOnColorsChangedListener(onColorsChangedListene, null);//3
WallpaperColors colorsSystem = wallpaperManager.getWallpaperColors(WallpaperManager.FLAG_SYSTEM);
updateTheme(colorsSystem);//4
因为系统主题是在android O上才有的,如果要app最低版本是android O以下,请做判断
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O_MR1) {
}
下面是SystemUI判断主题的代码片段
public void updateTheme(WallpaperColors colors) {
final boolean useDarkTheme = colors != null
&& (colors.getColorHints() & HINT_SUPPORTS_DARK_THEME) != 0;
}
打印log可以发现colors.getColorHints()在亮的时候是4,暗的时候是6,而HINT_SUPPORTS_DARK_THEME == 2
WallpaperColors这个类很多方法被hide修饰,包括getColorHints方法,导致非系统无法调用,如图
Android P后面又限制通过反射来调用系统API,直接调用这个方法是没戏了,但是这个类的toString方法又把这个值给打印出来了.
我们可以截取这个值,然后在判断,于是修改上面的判断
public void updateTheme(WallpaperColors colors) {
final boolean useDarkTheme = colors != null
&& (getColorHints(colors) & HINT_SUPPORTS_DARK_THEME) != 0;
}
private int getColorHints(WallpaperColors colors) {
String str = colors.toString();
int index = str.lastIndexOf("h: ");
String val = str.substring(index + 3, str.length() - 1);
if (TextUtils.isDigitsOnly(val)) {
return Integer.valueOf(val);
}
Log.e(TAG, "can not get getColorHints!!");
return 0;
}
改法不优雅,只能将就使用了
wallpaperManager.removeOnColorsChangedListener(onColorsChangedListener);
WallpaperColors源码解释:Provides information about the colors of a wallpaper.这个记录壁纸的color
WallpaperColors有几个有意思的方法
方法 | 返回类型 | 意义 |
---|---|---|
getPrimaryColor() | Color | 获取墙纸最具视觉代表性的颜色。 |
getSecondaryColor() | Color | 获得了壁纸的第二个最卓越的颜色。 |
getTertiaryColor() | Color | 获得了壁纸的第三个最卓越的颜色。 |
getMainColors() | List of Color | 按重要性排序的最杰出的颜色列表。 |
getColorHints() | int | 壁纸颜色提示的组合。(暗或者亮) |
calculateDarkHints(Bitmap source) | int | 根据传入的Bitmap,检查图像是否足够明亮 |
fromBitmap(@NonNull Bitmap bitmap) | WallpaperColors | 根据传入的Bitmap,检查图像返回WallpaperColors |
fromDrawable(Drawable drawable) | WallpaperColors | 根据传入的Drawable,检查图像返回WallpaperColors |
import android.app.WallpaperColors;
import android.app.WallpaperManager;
import android.content.Context;
import android.text.TextUtils;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
public final class ColorExtractor {
public interface ColorsChange {
public void themeChange(boolean useDarkTheme);
}
private static ColorExtractor colorExtractor;
private static final String TAG = "ColorExtractor";
private WallpaperManager wallpaperManager;
private static final int HINT_SUPPORTS_DARK_THEME = 1 << 1;
private WallpaperManager.OnColorsChangedListener onColorsChangedListene;
private List listens;
private ColorExtractor() {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O_MR1) {
onColorsChangedListene = new WallpaperManager.OnColorsChangedListener() {
@Override
public void onColorsChanged(WallpaperColors colors, int which) {
if (which == WallpaperManager.FLAG_SYSTEM) {
final boolean useDarkTheme = colors != null
&& (getColorHints(colors) & HINT_SUPPORTS_DARK_THEME) != 0;
if (listens != null && listens.size() > 0) {
for (ColorsChange colorsChange : listens) {
colorsChange.themeChange(useDarkTheme);
}
}
}
}
};
}
listens = new ArrayList<>();
}
public static ColorExtractor getInstance() {
if (colorExtractor == null) {
colorExtractor = new ColorExtractor();
}
return colorExtractor;
}
public void startListen(Context context) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O_MR1) {
if (wallpaperManager == null) {
wallpaperManager = WallpaperManager.getInstance(context.getApplicationContext());
}
WallpaperColors colorsSystem = wallpaperManager.getWallpaperColors(WallpaperManager.FLAG_SYSTEM);
final boolean useDarkTheme = colorsSystem != null
&& (getColorHints(colorsSystem) & HINT_SUPPORTS_DARK_THEME) != 0;
if (listens != null && listens.size() > 0) {
for (ColorsChange colorsChange : listens) {
colorsChange.themeChange(useDarkTheme);
}
}
wallpaperManager.addOnColorsChangedListener(onColorsChangedListene, null);
}
}
public void addThemeChange(ColorsChange colorsChange) {
if (!listens.contains(colorsChange)) {
listens.add(colorsChange);
}
}
public void removeThemeChange(ColorsChange colorsChange) {
if (listens.contains(colorsChange)) {
listens.remove(colorsChange);
}
}
public void stopListen() {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O_MR1) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O_MR1) {
wallpaperManager.removeOnColorsChangedListener(onColorsChangedListene);
}
if (listens != null) {
listens.clear();
}
}
}
private int getColorHints(WallpaperColors colors) {
String str = colors.toString();
int index = str.lastIndexOf("h: ");
String val = str.substring(index + 3, str.length() - 1);
if (TextUtils.isDigitsOnly(val)) {
return Integer.valueOf(val);
}
Log.e(TAG, "can not get getColorHints!!");
return 0;
}
}
//单例实例化
ColorExtractor colorExtractor = ColorExtractor.getInstance();
//注册监听事件,因为WallpaperManager注册的时候会调用初始主题,所以为了能获取初始值,所以在开始addThemeChange之前先注册监听事件.
colorExtractor.addThemeChange(new ColorExtractor.ColorsChange() {
@Override
public void themeChange(boolean useDarkTheme) {
Log.i(TAG, "useDarkTheme[" + useDarkTheme + "]");
}
});
//开始监听;一般在onStart(或onCreate)方法
colorExtractor.startListen(this);
//结束监听,一般在onStop(或onDestory)方法
colorExtractor.stopListen();