Adding compat implementation for the new WallpaperManager APIs for color extraction
Change-Id: Ie06c9ac3a77cd33d22ce298a55e234078895c3a0
This commit is contained in:
parent
db894b9bba
commit
3e93ec558a
|
@ -85,6 +85,11 @@
|
|||
android:process=":wallpaper_chooser">
|
||||
</service>
|
||||
|
||||
<service
|
||||
android:name="com.android.launcher3.compat.WallpaperManagerCompatVL$ColorExtractionService"
|
||||
android:exported="false"
|
||||
android:process=":wallpaper_chooser" />
|
||||
|
||||
<service android:name="com.android.launcher3.notification.NotificationListener"
|
||||
android:enabled="@bool/notification_badging_enabled"
|
||||
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* 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 com.android.launcher3.compat;
|
||||
|
||||
import android.util.SparseIntArray;
|
||||
|
||||
/**
|
||||
* A compatibility layer around platform implementation of WallpaperColors
|
||||
*/
|
||||
public class WallpaperColorsCompat {
|
||||
|
||||
private final SparseIntArray mColors;
|
||||
private final boolean mSupportsDarkText;
|
||||
|
||||
public WallpaperColorsCompat(SparseIntArray colors, boolean supportsDarkText) {
|
||||
mColors = colors;
|
||||
mSupportsDarkText = supportsDarkText;
|
||||
}
|
||||
|
||||
/**
|
||||
* A map of color code to their occurrences. The bigger the int, the more relevant the color.
|
||||
*/
|
||||
public SparseIntArray getColors() {
|
||||
return mColors;
|
||||
}
|
||||
|
||||
public boolean supportsDarkText() {
|
||||
return mSupportsDarkText;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* 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 com.android.launcher3.compat;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.Utilities;
|
||||
|
||||
public abstract class WallpaperManagerCompat {
|
||||
|
||||
private static final Object sInstanceLock = new Object();
|
||||
private static WallpaperManagerCompat sInstance;
|
||||
|
||||
public static WallpaperManagerCompat getInstance(Context context) {
|
||||
synchronized (sInstanceLock) {
|
||||
if (sInstance == null) {
|
||||
context = context.getApplicationContext();
|
||||
|
||||
if (Utilities.isAtLeastO()) {
|
||||
try {
|
||||
sInstance = new WallpaperManagerCompatVOMR1(context);
|
||||
} catch (Exception e) {
|
||||
// The wallpaper APIs do not yet exist
|
||||
}
|
||||
}
|
||||
if (sInstance == null) {
|
||||
sInstance = new WallpaperManagerCompatVL(context);
|
||||
}
|
||||
}
|
||||
return sInstance;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public abstract @Nullable WallpaperColorsCompat getWallpaperColors(int which);
|
||||
|
||||
public abstract void addOnColorsChangedListener(OnColorsChangedListenerCompat listener);
|
||||
|
||||
/**
|
||||
* Interface definition for a callback to be invoked when colors change on a wallpaper.
|
||||
*/
|
||||
public interface OnColorsChangedListenerCompat {
|
||||
|
||||
void onColorsChanged(WallpaperColorsCompat colors, int which);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,236 @@
|
|||
/*
|
||||
* 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 com.android.launcher3.compat;
|
||||
|
||||
import static android.app.WallpaperManager.FLAG_SYSTEM;
|
||||
|
||||
import android.app.IntentService;
|
||||
import android.app.WallpaperInfo;
|
||||
import android.app.WallpaperManager;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.BitmapRegionDecoder;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.ResultReceiver;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.graphics.Palette;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import android.util.SparseIntArray;
|
||||
|
||||
import com.android.launcher3.LauncherFiles;
|
||||
import com.android.launcher3.Utilities;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class WallpaperManagerCompatVL extends WallpaperManagerCompat {
|
||||
|
||||
private static final String TAG = "WMCompatVL";
|
||||
|
||||
private static final String VERSION_PREFIX = "1,";
|
||||
private static final String KEY_COLORS = "wallpaper_parsed_colors";
|
||||
private static final String EXTRA_RECEIVER = "receiver";
|
||||
|
||||
private final ArrayList<OnColorsChangedListenerCompat> mListeners = new ArrayList<>();
|
||||
|
||||
private final Context mContext;
|
||||
private WallpaperColorsCompat mColorsCompat;
|
||||
|
||||
WallpaperManagerCompatVL(Context context) {
|
||||
mContext = context;
|
||||
|
||||
String colors = prefs(mContext).getString(KEY_COLORS, "");
|
||||
int wallpaperId = -1;
|
||||
if (colors.startsWith(VERSION_PREFIX)) {
|
||||
Pair<Integer, WallpaperColorsCompat> storedValue = parseValue(colors);
|
||||
wallpaperId = storedValue.first;
|
||||
mColorsCompat = storedValue.second;
|
||||
}
|
||||
|
||||
if (wallpaperId == -1 || wallpaperId != getWallpaperId(context)) {
|
||||
reloadColors();
|
||||
}
|
||||
context.registerReceiver(new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
reloadColors();
|
||||
}
|
||||
}, new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public WallpaperColorsCompat getWallpaperColors(int which) {
|
||||
return which == FLAG_SYSTEM ? mColorsCompat : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addOnColorsChangedListener(OnColorsChangedListenerCompat listener) {
|
||||
mListeners.add(listener);
|
||||
}
|
||||
|
||||
private void reloadColors() {
|
||||
ResultReceiver receiver = new ResultReceiver(new Handler()) {
|
||||
|
||||
@Override
|
||||
protected void onReceiveResult(int resultCode, Bundle resultData) {
|
||||
handleResult(resultData.getString(KEY_COLORS));
|
||||
}
|
||||
};
|
||||
mContext.startService(new Intent(mContext, ColorExtractionService.class)
|
||||
.putExtra(EXTRA_RECEIVER, receiver));
|
||||
}
|
||||
|
||||
private void handleResult(String result) {
|
||||
prefs(mContext).edit().putString(KEY_COLORS, result).apply();
|
||||
mColorsCompat = parseValue(result).second;
|
||||
for (OnColorsChangedListenerCompat listener : mListeners) {
|
||||
listener.onColorsChanged(mColorsCompat, FLAG_SYSTEM);
|
||||
}
|
||||
}
|
||||
|
||||
private static SharedPreferences prefs(Context context) {
|
||||
return context.getSharedPreferences(
|
||||
LauncherFiles.DEVICE_PREFERENCES_KEY, Context.MODE_PRIVATE);
|
||||
}
|
||||
|
||||
private static final int getWallpaperId(Context context) {
|
||||
if (!Utilities.ATLEAST_NOUGAT) {
|
||||
return -1;
|
||||
}
|
||||
return context.getSystemService(WallpaperManager.class).getWallpaperId(FLAG_SYSTEM);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the stored value and returns the wallpaper id and wallpaper colors.
|
||||
*/
|
||||
private static Pair<Integer, WallpaperColorsCompat> parseValue(String value) {
|
||||
String[] parts = value.split(",");
|
||||
Integer wallpaperId = Integer.parseInt(parts[1]);
|
||||
if (parts.length == 2) {
|
||||
return Pair.create(wallpaperId, null);
|
||||
}
|
||||
|
||||
SparseIntArray colors = new SparseIntArray((parts.length - 2) / 2);
|
||||
for (int i = 2; i < parts.length; i += 2) {
|
||||
colors.put(Integer.parseInt(parts[i]), Integer.parseInt(parts[i + 1]));
|
||||
}
|
||||
return Pair.create(wallpaperId, new WallpaperColorsCompat(colors, false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Intent service to handle color extraction
|
||||
*/
|
||||
public static class ColorExtractionService extends IntentService {
|
||||
private static final int MAX_WALLPAPER_EXTRACTION_AREA = 112 * 112;
|
||||
|
||||
public ColorExtractionService() {
|
||||
super("ColorExtractionService");
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the wallpaper colors and sends the result back through the receiver.
|
||||
*/
|
||||
@Override
|
||||
protected void onHandleIntent(@Nullable Intent intent) {
|
||||
int wallpaperId = getWallpaperId(this);
|
||||
|
||||
Bitmap bitmap = null;
|
||||
Drawable drawable = null;
|
||||
|
||||
WallpaperManager wm = WallpaperManager.getInstance(this);
|
||||
WallpaperInfo info = wm.getWallpaperInfo();
|
||||
if (info != null) {
|
||||
// For live wallpaper, extract colors from thumbnail
|
||||
drawable = info.loadThumbnail(getPackageManager());
|
||||
} else {
|
||||
if (Utilities.ATLEAST_NOUGAT) {
|
||||
try (ParcelFileDescriptor fd = wm.getWallpaperFile(FLAG_SYSTEM)) {
|
||||
BitmapRegionDecoder decoder = BitmapRegionDecoder
|
||||
.newInstance(fd.getFileDescriptor(), false);
|
||||
|
||||
int requestedArea = decoder.getWidth() * decoder.getHeight();
|
||||
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
|
||||
if (requestedArea > MAX_WALLPAPER_EXTRACTION_AREA) {
|
||||
double areaRatio =
|
||||
MAX_WALLPAPER_EXTRACTION_AREA / (double) requestedArea;
|
||||
double nearestPowOf2 =
|
||||
Math.floor(Math.log(areaRatio) / (2 * Math.log(2)));
|
||||
options.inSampleSize = (int) Math.pow(2, nearestPowOf2);
|
||||
}
|
||||
Rect region = new Rect(0, 0, decoder.getWidth(), decoder.getHeight());
|
||||
bitmap = decoder.decodeRegion(region, options);
|
||||
decoder.recycle();
|
||||
} catch (IOException | NullPointerException e) {
|
||||
Log.e(TAG, "Fetching partial bitmap failed, trying old method", e);
|
||||
}
|
||||
}
|
||||
if (bitmap == null) {
|
||||
drawable = wm.getDrawable();
|
||||
}
|
||||
}
|
||||
|
||||
if (drawable != null) {
|
||||
// Calculate how big the bitmap needs to be.
|
||||
// This avoids unnecessary processing and allocation inside Palette.
|
||||
final int requestedArea = drawable.getIntrinsicWidth() *
|
||||
drawable.getIntrinsicHeight();
|
||||
double scale = 1;
|
||||
if (requestedArea > MAX_WALLPAPER_EXTRACTION_AREA) {
|
||||
scale = Math.sqrt(MAX_WALLPAPER_EXTRACTION_AREA / (double) requestedArea);
|
||||
}
|
||||
bitmap = Bitmap.createBitmap((int) (drawable.getIntrinsicWidth() * scale),
|
||||
(int) (drawable.getIntrinsicHeight() * scale), Bitmap.Config.ARGB_8888);
|
||||
final Canvas bmpCanvas = new Canvas(bitmap);
|
||||
drawable.setBounds(0, 0, bitmap.getWidth(), bitmap.getHeight());
|
||||
drawable.draw(bmpCanvas);
|
||||
}
|
||||
|
||||
String value = VERSION_PREFIX + wallpaperId;
|
||||
|
||||
if (bitmap != null) {
|
||||
Palette palette = Palette.from(bitmap).generate();
|
||||
bitmap.recycle();
|
||||
|
||||
StringBuilder builder = new StringBuilder(value);
|
||||
for (Palette.Swatch swatch : palette.getSwatches()) {
|
||||
builder.append(',')
|
||||
.append(swatch.getRgb())
|
||||
.append(',')
|
||||
.append(swatch.getPopulation());
|
||||
}
|
||||
value = builder.toString();
|
||||
}
|
||||
|
||||
ResultReceiver receiver = intent.getParcelableExtra(EXTRA_RECEIVER);
|
||||
Bundle result = new Bundle();
|
||||
result.putString(KEY_COLORS, value);
|
||||
receiver.send(0, result);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* 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 com.android.launcher3.compat;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.WallpaperManager;
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.os.Build;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import android.util.SparseIntArray;
|
||||
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.List;
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.O)
|
||||
public class WallpaperManagerCompatVOMR1 extends WallpaperManagerCompat {
|
||||
|
||||
private static final String TAG = "WMCompatVOMR1";
|
||||
|
||||
private final WallpaperManager mWm;
|
||||
|
||||
private final Class mOCLClass;
|
||||
private final Method mAddOCLMethod;
|
||||
|
||||
private final Method mWCGetMethod;
|
||||
private final Method mWCGetColorsMethod;
|
||||
private final Method mWCSupportsDarkTextMethod;
|
||||
|
||||
WallpaperManagerCompatVOMR1(Context context) throws Exception {
|
||||
mWm = context.getSystemService(WallpaperManager.class);
|
||||
|
||||
mOCLClass = Class.forName("android.app.WallpaperManager$OnColorsChangedListener");
|
||||
mAddOCLMethod = WallpaperManager.class.getDeclaredMethod(
|
||||
"addOnColorsChangedListener", mOCLClass);
|
||||
|
||||
mWCGetMethod = WallpaperManager.class.getDeclaredMethod("getWallpaperColors", int.class);
|
||||
Class wallpaperColorsClass = mWCGetMethod.getReturnType();
|
||||
mWCGetColorsMethod = wallpaperColorsClass.getDeclaredMethod("getColors");
|
||||
mWCSupportsDarkTextMethod = wallpaperColorsClass.getDeclaredMethod("supportsDarkText");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public WallpaperColorsCompat getWallpaperColors(int which) {
|
||||
try {
|
||||
return convertColorsObject(mWCGetMethod.invoke(mWm, which));
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error calling wallpaper API", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addOnColorsChangedListener(final OnColorsChangedListenerCompat listener) {
|
||||
Object onChangeListener = Proxy.newProxyInstance(
|
||||
WallpaperManager.class.getClassLoader(),
|
||||
new Class[]{mOCLClass},
|
||||
new InvocationHandler() {
|
||||
@Override
|
||||
public Object invoke(Object o, Method method, Object[] objects)
|
||||
throws Throwable {
|
||||
String methodName = method.getName();
|
||||
if ("onColorsChanged".equals(methodName)) {
|
||||
listener.onColorsChanged(
|
||||
convertColorsObject(objects[0]), (Integer) objects[1]);
|
||||
} else if ("toString".equals(methodName)) {
|
||||
return listener.toString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
try {
|
||||
mAddOCLMethod.invoke(mWm, onChangeListener);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error calling wallpaper API", e);
|
||||
}
|
||||
}
|
||||
|
||||
private WallpaperColorsCompat convertColorsObject(Object colors) throws Exception {
|
||||
if (colors == null) {
|
||||
return null;
|
||||
}
|
||||
List<Pair<Color, Integer>> list = (List) mWCGetColorsMethod.invoke(colors);
|
||||
boolean supportsDarkText = (Boolean) mWCSupportsDarkTextMethod.invoke(colors);
|
||||
SparseIntArray colorMap = new SparseIntArray(list.size());
|
||||
for (Pair<Color, Integer> color : list) {
|
||||
colorMap.put(color.first.toArgb(), color.second);
|
||||
}
|
||||
return new WallpaperColorsCompat(colorMap, supportsDarkText);
|
||||
}
|
||||
}
|
|
@ -170,7 +170,7 @@ public class ExtractedColors {
|
|||
try {
|
||||
WallpaperManager.class.getDeclaredMethod("getWallpaperColors", int.class);
|
||||
ColorExtractor extractor = new ColorExtractor(context);
|
||||
ColorExtractor.GradientColors colors = extractor.getColors(WallpaperManager.FLAG_SYSTEM);
|
||||
ColorExtractor.GradientColors colors = extractor.getColors();
|
||||
setColorAtIndex(ALLAPPS_GRADIENT_MAIN_INDEX, colors.getMainColor());
|
||||
setColorAtIndex(ALLAPPS_GRADIENT_SECONDARY_INDEX, colors.getSecondaryColor());
|
||||
} catch (NoSuchMethodException e) {
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
package com.android.launcher3.dynamicui.colorextraction;
|
||||
|
||||
import android.app.WallpaperManager;
|
||||
import static android.app.WallpaperManager.FLAG_SYSTEM;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.os.Parcelable;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.launcher3.compat.WallpaperColorsCompat;
|
||||
import com.android.launcher3.compat.WallpaperManagerCompat;
|
||||
import com.android.launcher3.dynamicui.colorextraction.types.ExtractionType;
|
||||
import com.android.launcher3.dynamicui.colorextraction.types.Tonal;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
|
||||
/**
|
||||
* Class to process wallpaper colors and generate a tonal palette based on them.
|
||||
|
@ -18,59 +17,32 @@ import java.lang.reflect.Method;
|
|||
* TODO remove this class if available by platform
|
||||
*/
|
||||
public class ColorExtractor {
|
||||
private static final String TAG = "ColorExtractor";
|
||||
private static final int FALLBACK_COLOR = Color.WHITE;
|
||||
|
||||
private final Context mContext;
|
||||
private int mMainFallbackColor = FALLBACK_COLOR;
|
||||
private int mSecondaryFallbackColor = FALLBACK_COLOR;
|
||||
private final GradientColors mSystemColors;
|
||||
private final GradientColors mLockColors;
|
||||
private final Context mContext;
|
||||
private final ExtractionType mExtractionType;
|
||||
|
||||
public ColorExtractor(Context context) {
|
||||
mContext = context;
|
||||
mSystemColors = new GradientColors();
|
||||
mLockColors = new GradientColors();
|
||||
mExtractionType = new Tonal();
|
||||
WallpaperManager wallpaperManager = mContext.getSystemService(WallpaperManager.class);
|
||||
|
||||
if (wallpaperManager == null) {
|
||||
Log.w(TAG, "Can't listen to color changes!");
|
||||
} else {
|
||||
Parcelable wallpaperColorsObj;
|
||||
try {
|
||||
Method method = WallpaperManager.class
|
||||
.getDeclaredMethod("getWallpaperColors", int.class);
|
||||
|
||||
wallpaperColorsObj = (Parcelable) method.invoke(wallpaperManager,
|
||||
WallpaperManager.FLAG_SYSTEM);
|
||||
extractInto(new WallpaperColorsCompat(wallpaperColorsObj), mSystemColors);
|
||||
wallpaperColorsObj = (Parcelable) method.invoke(wallpaperManager,
|
||||
WallpaperManager.FLAG_LOCK);
|
||||
extractInto(new WallpaperColorsCompat(wallpaperColorsObj), mLockColors);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "reflection failed", e);
|
||||
}
|
||||
}
|
||||
extractFrom(WallpaperManagerCompat.getInstance(context).getWallpaperColors(FLAG_SYSTEM));
|
||||
}
|
||||
|
||||
public GradientColors getColors(int which) {
|
||||
if (which == WallpaperManager.FLAG_LOCK) {
|
||||
return mLockColors;
|
||||
} else if (which == WallpaperManager.FLAG_SYSTEM) {
|
||||
return mSystemColors;
|
||||
} else {
|
||||
throw new IllegalArgumentException("which should be either FLAG_SYSTEM or FLAG_LOCK");
|
||||
}
|
||||
public GradientColors getColors() {
|
||||
return mSystemColors;
|
||||
}
|
||||
|
||||
private void extractInto(WallpaperColorsCompat inWallpaperColors, GradientColors outGradientColors) {
|
||||
applyFallback(outGradientColors);
|
||||
private void extractFrom(WallpaperColorsCompat inWallpaperColors) {
|
||||
applyFallback(mSystemColors);
|
||||
if (inWallpaperColors == null) {
|
||||
return;
|
||||
}
|
||||
mExtractionType.extractInto(inWallpaperColors, outGradientColors);
|
||||
mExtractionType.extractInto(inWallpaperColors, mSystemColors);
|
||||
}
|
||||
|
||||
private void applyFallback(GradientColors outGradientColors) {
|
||||
|
|
|
@ -1,69 +0,0 @@
|
|||
package com.android.launcher3.dynamicui.colorextraction;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.util.Pair;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A wrapper around platform implementation of WallpaperColors until the
|
||||
* updated SDK is available.
|
||||
*
|
||||
* TODO remove this class if available by platform
|
||||
*/
|
||||
public class WallpaperColorsCompat implements Parcelable {
|
||||
|
||||
private final Parcelable mObject;
|
||||
|
||||
public WallpaperColorsCompat(Parcelable object) {
|
||||
mObject = object;
|
||||
}
|
||||
|
||||
private Object invokeMethod(String methodName) {
|
||||
try {
|
||||
return mObject.getClass().getDeclaredMethod(methodName).invoke(mObject);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel parcel, int i) {
|
||||
parcel.writeParcelable(mObject, i);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<WallpaperColorsCompat> CREATOR =
|
||||
new Parcelable.Creator<WallpaperColorsCompat>() {
|
||||
public WallpaperColorsCompat createFromParcel(Parcel source) {
|
||||
Parcelable object = source.readParcelable(null);
|
||||
return new WallpaperColorsCompat(object);
|
||||
}
|
||||
|
||||
public WallpaperColorsCompat[] newArray(int size) {
|
||||
return new WallpaperColorsCompat[size];
|
||||
}
|
||||
};
|
||||
|
||||
public List<Pair<Color, Integer>> getColors() {
|
||||
try {
|
||||
return (List<Pair<Color, Integer>>) invokeMethod("getColors");
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean supportsDarkText() {
|
||||
try {
|
||||
return (Boolean) invokeMethod("supportsDarkText");
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
package com.android.launcher3.dynamicui.colorextraction.types;
|
||||
|
||||
import com.android.launcher3.compat.WallpaperColorsCompat;
|
||||
import com.android.launcher3.dynamicui.colorextraction.ColorExtractor;
|
||||
import com.android.launcher3.dynamicui.colorextraction.WallpaperColorsCompat;
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -6,11 +6,15 @@ import android.support.annotation.Nullable;
|
|||
import android.support.v4.graphics.ColorUtils;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import android.util.SparseIntArray;
|
||||
|
||||
import com.android.launcher3.compat.WallpaperColorsCompat;
|
||||
import com.android.launcher3.dynamicui.colorextraction.ColorExtractor;
|
||||
import com.android.launcher3.dynamicui.colorextraction.WallpaperColorsCompat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -29,9 +33,10 @@ public class Tonal implements ExtractionType {
|
|||
private static final float MIN_COLOR_OCCURRENCE = 0.1f;
|
||||
private static final float MIN_LUMINOSITY = 0.5f;
|
||||
|
||||
public void extractInto(WallpaperColorsCompat wallpaperColors,
|
||||
ColorExtractor.GradientColors gradientColors) {
|
||||
if (wallpaperColors.getColors().size() == 0) {
|
||||
public void extractInto(
|
||||
WallpaperColorsCompat wallpaperColors, ColorExtractor.GradientColors gradientColors) {
|
||||
SparseIntArray colorsArray = wallpaperColors.getColors();
|
||||
if (colorsArray.size() == 0) {
|
||||
return;
|
||||
}
|
||||
// Tonal is not really a sort, it takes a color from the extracted
|
||||
|
@ -39,24 +44,30 @@ public class Tonal implements ExtractionType {
|
|||
// palettes. The best fit is tweaked to be closer to the source color
|
||||
// and replaces the original palette
|
||||
|
||||
List<Pair<Integer, Integer>> colors = new ArrayList<>(colorsArray.size());
|
||||
for (int i = colorsArray.size() - 1; i >= 0; i --) {
|
||||
colors.add(Pair.create(colorsArray.keyAt(i), colorsArray.valueAt(i)));
|
||||
}
|
||||
|
||||
// First find the most representative color in the image
|
||||
populationSort(wallpaperColors);
|
||||
populationSort(colors);
|
||||
|
||||
// Calculate total
|
||||
int total = 0;
|
||||
for (Pair<Color, Integer> weightedColor : wallpaperColors.getColors()) {
|
||||
for (Pair<Integer, Integer> weightedColor : colors) {
|
||||
total += weightedColor.second;
|
||||
}
|
||||
|
||||
// Get bright colors that occur often enough in this image
|
||||
Pair<Color, Integer> bestColor = null;
|
||||
Pair<Integer, Integer> bestColor = null;
|
||||
float[] hsl = new float[3];
|
||||
for (Pair<Color, Integer> weightedColor : wallpaperColors.getColors()) {
|
||||
for (Pair<Integer, Integer> weightedColor : colors) {
|
||||
float colorOccurrence = weightedColor.second / (float) total;
|
||||
if (colorOccurrence < MIN_COLOR_OCCURRENCE) {
|
||||
break;
|
||||
}
|
||||
|
||||
int colorValue = weightedColor.first.toArgb();
|
||||
int colorValue = weightedColor.first;
|
||||
ColorUtils.RGBToHSL(Color.red(colorValue), Color.green(colorValue),
|
||||
Color.blue(colorValue), hsl);
|
||||
if (hsl[2] > MIN_LUMINOSITY) {
|
||||
|
@ -66,10 +77,10 @@ public class Tonal implements ExtractionType {
|
|||
|
||||
// Fallback to first color
|
||||
if (bestColor == null) {
|
||||
bestColor = wallpaperColors.getColors().get(0);
|
||||
bestColor = colors.get(0);
|
||||
}
|
||||
|
||||
int colorValue = bestColor.first.toArgb();
|
||||
int colorValue = bestColor.first;
|
||||
ColorUtils.RGBToHSL(Color.red(colorValue), Color.green(colorValue), Color.blue(colorValue),
|
||||
hsl);
|
||||
hsl[0] /= 360.0f; // normalize
|
||||
|
@ -105,10 +116,10 @@ public class Tonal implements ExtractionType {
|
|||
gradientColors.setSecondaryColor(ColorUtils.HSLToColor(hsl));
|
||||
}
|
||||
|
||||
private static void populationSort(@NonNull WallpaperColorsCompat wallpaperColors) {
|
||||
wallpaperColors.getColors().sort(new Comparator<Pair<Color, Integer>>() {
|
||||
private static void populationSort(@NonNull List<Pair<Integer, Integer>> wallpaperColors) {
|
||||
Collections.sort(wallpaperColors, new Comparator<Pair<Integer, Integer>>() {
|
||||
@Override
|
||||
public int compare(Pair<Color, Integer> a, Pair<Color, Integer> b) {
|
||||
public int compare(Pair<Integer, Integer> a, Pair<Integer, Integer> b) {
|
||||
return b.second - a.second;
|
||||
}
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue