Merge "Wallpaper color extraction"
This commit is contained in:
@@ -22,6 +22,7 @@ import android.os.ParcelFileDescriptor;
|
||||
import android.app.IWallpaperManagerCallback;
|
||||
import android.app.WallpaperInfo;
|
||||
import android.content.ComponentName;
|
||||
import android.app.WallpaperColors;
|
||||
|
||||
/** @hide */
|
||||
interface IWallpaperManager {
|
||||
@@ -135,4 +136,23 @@ interface IWallpaperManager {
|
||||
* wallpaper content has changed.
|
||||
*/
|
||||
boolean setLockWallpaperCallback(IWallpaperManagerCallback cb);
|
||||
|
||||
/**
|
||||
* Returns the colors used by the lock screen or system wallpaper.
|
||||
*
|
||||
* @param which either {@link WallpaperManager#FLAG_LOCK}
|
||||
* or {@link WallpaperManager#FLAG_SYSTEM}
|
||||
* @return colors of chosen wallpaper
|
||||
*/
|
||||
WallpaperColors getWallpaperColors(int which);
|
||||
|
||||
/**
|
||||
* Register a callback to receive color updates
|
||||
*/
|
||||
void registerWallpaperColorsCallback(IWallpaperManagerCallback cb);
|
||||
|
||||
/**
|
||||
* Unregister a callback that was receiving color updates
|
||||
*/
|
||||
void unregisterWallpaperColorsCallback(IWallpaperManagerCallback cb);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package android.app;
|
||||
|
||||
import android.app.WallpaperColors;
|
||||
|
||||
/**
|
||||
* Callback interface used by IWallpaperManager to send asynchronous
|
||||
* notifications back to its clients. Note that this is a
|
||||
@@ -28,4 +30,10 @@ oneway interface IWallpaperManagerCallback {
|
||||
* Called when the wallpaper has changed
|
||||
*/
|
||||
void onWallpaperChanged();
|
||||
|
||||
/**
|
||||
* Called when wallpaper colors change
|
||||
*/
|
||||
void onWallpaperColorsChanged(in WallpaperColors colors, int which);
|
||||
|
||||
}
|
||||
|
||||
19
core/java/android/app/WallpaperColors.aidl
Normal file
19
core/java/android/app/WallpaperColors.aidl
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* 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 android.app;
|
||||
|
||||
parcelable WallpaperColors;
|
||||
@@ -22,6 +22,7 @@ import android.os.Parcelable;
|
||||
|
||||
import android.util.Pair;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -29,7 +30,19 @@ import java.util.List;
|
||||
*/
|
||||
public final class WallpaperColors implements Parcelable {
|
||||
|
||||
private static final float BRIGHT_LUMINANCE = 0.9f;
|
||||
private final List<Pair<Color, Integer>> mColors;
|
||||
private final boolean mSupportsDarkText;
|
||||
|
||||
public WallpaperColors(Parcel parcel) {
|
||||
mColors = new ArrayList<>();
|
||||
int count = parcel.readInt();
|
||||
for (int i=0; i < count; i++) {
|
||||
Color color = Color.valueOf(parcel.readInt());
|
||||
int weight = parcel.readInt();
|
||||
mColors.add(new Pair<>(color, weight));
|
||||
}
|
||||
mSupportsDarkText = parcel.readBoolean();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -43,6 +56,7 @@ public final class WallpaperColors implements Parcelable {
|
||||
* and number of occurrences/influence.
|
||||
*/
|
||||
public WallpaperColors(List<Pair<Color, Integer>> colors) {
|
||||
this(colors, calculateDarkTextSupport(colors));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -55,6 +69,10 @@ public final class WallpaperColors implements Parcelable {
|
||||
* @param supportsDarkText can have dark text on top or not
|
||||
*/
|
||||
public WallpaperColors(List<Pair<Color, Integer>> colors, boolean supportsDarkText) {
|
||||
if (colors == null)
|
||||
colors = new ArrayList<>();
|
||||
mColors = colors;
|
||||
mSupportsDarkText = supportsDarkText;
|
||||
}
|
||||
|
||||
public static final Creator<WallpaperColors> CREATOR = new Creator<WallpaperColors>() {
|
||||
@@ -76,6 +94,13 @@ public final class WallpaperColors implements Parcelable {
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
int count = mColors.size();
|
||||
dest.writeInt(count);
|
||||
for (Pair<Color, Integer> color : mColors) {
|
||||
dest.writeInt(color.first.toArgb());
|
||||
dest.writeInt(color.second);
|
||||
}
|
||||
dest.writeBoolean(mSupportsDarkText);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -83,7 +108,22 @@ public final class WallpaperColors implements Parcelable {
|
||||
* @return list of colors paired with their weights.
|
||||
*/
|
||||
public List<Pair<Color, Integer>> getColors() {
|
||||
return null;
|
||||
return mColors;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
WallpaperColors other = (WallpaperColors) o;
|
||||
return mColors.equals(other.mColors) && mSupportsDarkText == other.mSupportsDarkText;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 31 * mColors.hashCode() + (mSupportsDarkText ? 1 : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,6 +132,24 @@ public final class WallpaperColors implements Parcelable {
|
||||
* @return true if dark text is supported
|
||||
*/
|
||||
public boolean supportsDarkText() {
|
||||
return false;
|
||||
return mSupportsDarkText;
|
||||
}
|
||||
|
||||
private static boolean calculateDarkTextSupport(List<Pair<Color, Integer>> colors) {
|
||||
if (colors == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Pair<Color, Integer> mainColor = null;
|
||||
|
||||
for (Pair<Color, Integer> color : colors) {
|
||||
if (mainColor == null) {
|
||||
mainColor = color;
|
||||
} else if (color.second > mainColor.second) {
|
||||
mainColor = color;
|
||||
}
|
||||
}
|
||||
return mainColor != null &&
|
||||
mainColor.first.luminance() > BRIGHT_LUMINANCE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,13 +52,13 @@ import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.SystemProperties;
|
||||
import android.os.UserHandle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import android.view.WindowManagerGlobal;
|
||||
|
||||
import libcore.io.IoUtils;
|
||||
@@ -71,6 +71,8 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@@ -271,15 +273,20 @@ public class WallpaperManager {
|
||||
}
|
||||
}
|
||||
|
||||
static class Globals extends IWallpaperManagerCallback.Stub {
|
||||
private static class Globals extends IWallpaperManagerCallback.Stub {
|
||||
private final IWallpaperManager mService;
|
||||
private boolean mColorCallbackRegistered;
|
||||
private final ArrayList<Pair<OnColorsChangedListener, Handler>> mColorListeners =
|
||||
new ArrayList<>();
|
||||
private Bitmap mCachedWallpaper;
|
||||
private int mCachedWallpaperUserId;
|
||||
private Bitmap mDefaultWallpaper;
|
||||
private Handler mMainLooperHandler;
|
||||
|
||||
Globals(Looper looper) {
|
||||
IBinder b = ServiceManager.getService(Context.WALLPAPER_SERVICE);
|
||||
mService = IWallpaperManager.Stub.asInterface(b);
|
||||
mMainLooperHandler = new Handler(looper);
|
||||
forgetLoadedWallpaper();
|
||||
}
|
||||
|
||||
@@ -292,6 +299,88 @@ public class WallpaperManager {
|
||||
forgetLoadedWallpaper();
|
||||
}
|
||||
|
||||
/**
|
||||
* Start listening to wallpaper color events.
|
||||
* Will be called whenever someone changes their wallpaper or if a live wallpaper
|
||||
* changes its colors.
|
||||
* @param callback Listener
|
||||
* @param handler Thread to call it from. Main thread if null.
|
||||
*/
|
||||
public void addOnColorsChangedListener(@NonNull OnColorsChangedListener callback,
|
||||
@Nullable Handler handler) {
|
||||
synchronized (this) {
|
||||
if (!mColorCallbackRegistered) {
|
||||
try {
|
||||
mService.registerWallpaperColorsCallback(this);
|
||||
mColorCallbackRegistered = true;
|
||||
} catch (RemoteException e) {
|
||||
// Failed, service is gone
|
||||
Log.w(TAG, "Can't register for color updates", e);
|
||||
}
|
||||
}
|
||||
mColorListeners.add(new Pair<>(callback, handler));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop listening to wallpaper color events.
|
||||
*
|
||||
* @param callback listener
|
||||
*/
|
||||
public void removeOnColorsChangedListener(@NonNull OnColorsChangedListener callback) {
|
||||
synchronized (this) {
|
||||
mColorListeners.removeIf(pair -> pair.first == callback);
|
||||
|
||||
if (mColorListeners.size() == 0 && mColorCallbackRegistered) {
|
||||
mColorCallbackRegistered = false;
|
||||
try {
|
||||
mService.unregisterWallpaperColorsCallback(this);
|
||||
} catch (RemoteException e) {
|
||||
// Failed, service is gone
|
||||
Log.w(TAG, "Can't unregister color updates", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWallpaperColorsChanged(WallpaperColors colors, int which) {
|
||||
synchronized (this) {
|
||||
for (Pair<OnColorsChangedListener, Handler> listener : mColorListeners) {
|
||||
Handler handler = listener.second;
|
||||
if (listener.second == null) {
|
||||
handler = mMainLooperHandler;
|
||||
}
|
||||
handler.post(() -> {
|
||||
// Dealing with race conditions between posting a callback and
|
||||
// removeOnColorsChangedListener being called.
|
||||
boolean stillExists;
|
||||
synchronized (sGlobals) {
|
||||
stillExists = mColorListeners.contains(listener);
|
||||
}
|
||||
if (stillExists) {
|
||||
listener.first.onColorsChanged(colors, which);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WallpaperColors getWallpaperColors(int which) {
|
||||
synchronized (this) {
|
||||
if (which != FLAG_LOCK && which != FLAG_SYSTEM)
|
||||
throw new IllegalArgumentException(
|
||||
"which should be either FLAG_LOCK or FLAG_SYSTEM");
|
||||
|
||||
try {
|
||||
return mService.getWallpaperColors(which);
|
||||
} catch (RemoteException e) {
|
||||
// Can't get colors, connection lost.
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public Bitmap peekWallpaperBitmap(Context context, boolean returnDefault,
|
||||
@SetWallpaperFlags int which) {
|
||||
return peekWallpaperBitmap(context, returnDefault, which, context.getUserId());
|
||||
@@ -746,7 +835,6 @@ public class WallpaperManager {
|
||||
return getWallpaperFile(which, mContext.getUserId());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Registers a listener to get notified when the wallpaper colors change.
|
||||
* Callback might be called from an arbitrary background thread.
|
||||
@@ -754,16 +842,18 @@ public class WallpaperManager {
|
||||
* @param listener A listener to register
|
||||
*/
|
||||
public void addOnColorsChangedListener(@NonNull OnColorsChangedListener listener) {
|
||||
sGlobals.addOnColorsChangedListener(listener, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a listener to get notified when the wallpaper colors change
|
||||
* @param listener A listener to register
|
||||
* @param handler Where to call it from. Might be called from a background thread
|
||||
* @param handler Where to call it from. Will be called from the main thread
|
||||
* if null.
|
||||
*/
|
||||
public void addOnColorsChangedListener(@NonNull OnColorsChangedListener listener,
|
||||
@Nullable Handler handler) {
|
||||
@NonNull Handler handler) {
|
||||
sGlobals.addOnColorsChangedListener(listener, handler);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -771,6 +861,7 @@ public class WallpaperManager {
|
||||
* @param callback A callback to unsubscribe
|
||||
*/
|
||||
public void removeOnColorsChangedListener(@NonNull OnColorsChangedListener callback) {
|
||||
sGlobals.removeOnColorsChangedListener(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -780,7 +871,7 @@ public class WallpaperManager {
|
||||
* @return a list of colors ordered by priority
|
||||
*/
|
||||
public @Nullable WallpaperColors getWallpaperColors(int which) {
|
||||
return null;
|
||||
return sGlobals.getWallpaperColors(which);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1773,6 +1864,12 @@ public class WallpaperManager {
|
||||
public void onWallpaperChanged() throws RemoteException {
|
||||
mLatch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWallpaperColorsChanged(WallpaperColors colors, int which)
|
||||
throws RemoteException {
|
||||
sGlobals.onWallpaperColorsChanged(colors, which);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,6 +18,7 @@ package android.service.wallpaper;
|
||||
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.service.wallpaper.IWallpaperEngine;
|
||||
import android.app.WallpaperColors;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
@@ -26,4 +27,5 @@ interface IWallpaperConnection {
|
||||
void attachEngine(IWallpaperEngine engine);
|
||||
void engineShown(IWallpaperEngine engine);
|
||||
ParcelFileDescriptor setWallpaper(String name);
|
||||
void onWallpaperColorsChanged(in WallpaperColors colors);
|
||||
}
|
||||
|
||||
@@ -30,5 +30,5 @@ oneway interface IWallpaperEngine {
|
||||
void dispatchPointer(in MotionEvent event);
|
||||
void dispatchWallpaperCommand(String action, int x, int y,
|
||||
int z, in Bundle extras);
|
||||
void destroy();
|
||||
void destroy();
|
||||
}
|
||||
|
||||
@@ -550,6 +550,12 @@ public abstract class WallpaperService extends Service {
|
||||
* This will trigger a {@link #onComputeWallpaperColors()} call.
|
||||
*/
|
||||
public void invalidateColors() {
|
||||
try {
|
||||
mConnection.onWallpaperColorsChanged(onComputeWallpaperColors());
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Can't invalidate wallpaper colors because " +
|
||||
"wallpaper connection was lost", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -562,7 +568,7 @@ public abstract class WallpaperService extends Service {
|
||||
public @Nullable WallpaperColors onComputeWallpaperColors() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
protected void dump(String prefix, FileDescriptor fd, PrintWriter out, String[] args) {
|
||||
out.print(prefix); out.print("mInitializing="); out.print(mInitializing);
|
||||
out.print(" mDestroyed="); out.println(mDestroyed);
|
||||
@@ -1199,6 +1205,7 @@ public abstract class WallpaperService extends Service {
|
||||
mEngine = engine;
|
||||
mActiveEngines.add(engine);
|
||||
engine.attach(this);
|
||||
engine.invalidateColors();
|
||||
return;
|
||||
}
|
||||
case DO_DETACH: {
|
||||
|
||||
@@ -36,6 +36,7 @@ import android.os.ParcelFileDescriptor;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.UserHandle;
|
||||
import android.app.WallpaperColors;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.keyguard.KeyguardUpdateMonitor;
|
||||
@@ -156,6 +157,11 @@ public class LockscreenWallpaper extends IWallpaperManagerCallback.Stub implemen
|
||||
postUpdateWallpaper();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWallpaperColorsChanged(WallpaperColors colors, int which) {
|
||||
|
||||
}
|
||||
|
||||
private void postUpdateWallpaper() {
|
||||
mH.removeCallbacks(this);
|
||||
mH.post(this);
|
||||
|
||||
@@ -52,6 +52,7 @@ import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.BitmapRegionDecoder;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Binder;
|
||||
@@ -73,10 +74,12 @@ import android.os.UserManager;
|
||||
import android.service.wallpaper.IWallpaperConnection;
|
||||
import android.service.wallpaper.IWallpaperEngine;
|
||||
import android.service.wallpaper.IWallpaperService;
|
||||
import android.app.WallpaperColors;
|
||||
import android.service.wallpaper.WallpaperService;
|
||||
import android.system.ErrnoException;
|
||||
import android.system.Os;
|
||||
import android.util.EventLog;
|
||||
import android.util.Pair;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
import android.util.Xml;
|
||||
@@ -86,6 +89,7 @@ import android.view.WindowManager;
|
||||
|
||||
import com.android.internal.R;
|
||||
import com.android.internal.content.PackageMonitor;
|
||||
import com.android.internal.graphics.palette.Palette;
|
||||
import com.android.internal.os.BackgroundThread;
|
||||
import com.android.internal.util.DumpUtils;
|
||||
import com.android.internal.util.FastXmlSerializer;
|
||||
@@ -94,6 +98,7 @@ import com.android.server.EventLogTags;
|
||||
import com.android.server.FgThread;
|
||||
import com.android.server.SystemService;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import libcore.io.IoUtils;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
@@ -219,6 +224,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
|
||||
// lock-only changes happen on the dedicated lock wallpaper input file
|
||||
final boolean sysWallpaperChanged = (mWallpaperFile.equals(changedFile));
|
||||
final boolean lockWallpaperChanged = (mWallpaperLockFile.equals(changedFile));
|
||||
int notifyColorsWhich = 0;
|
||||
WallpaperData wallpaper = dataForEvent(sysWallpaperChanged, lockWallpaperChanged);
|
||||
|
||||
if (DEBUG) {
|
||||
@@ -240,6 +246,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
|
||||
}
|
||||
SELinux.restorecon(changedFile);
|
||||
notifyLockWallpaperChanged();
|
||||
notifyWallpaperColorsChanged(wallpaper, FLAG_LOCK);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -284,6 +291,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
|
||||
// If this was the system wallpaper, rebind...
|
||||
bindWallpaperComponentLocked(mImageWallpaper, true,
|
||||
false, wallpaper, null);
|
||||
notifyColorsWhich |= FLAG_SYSTEM;
|
||||
}
|
||||
if (lockWallpaperChanged
|
||||
|| (wallpaper.whichPending & FLAG_LOCK) != 0) {
|
||||
@@ -298,12 +306,19 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
|
||||
}
|
||||
// and in any case, tell keyguard about it
|
||||
notifyLockWallpaperChanged();
|
||||
notifyColorsWhich |= FLAG_LOCK;
|
||||
}
|
||||
|
||||
saveSettingsLocked(wallpaper.userId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Outside of the lock since it will synchronize itself
|
||||
if (notifyColorsWhich != 0) {
|
||||
notifyWallpaperColorsChanged(wallpaper, notifyColorsWhich);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -318,6 +333,90 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyWallpaperColorsChanged(WallpaperData wallpaper, int which) {
|
||||
boolean needsExtraction;
|
||||
synchronized (mLock) {
|
||||
if (mColorsChangedListeners.getRegisteredCallbackCount() == 0)
|
||||
return;
|
||||
|
||||
if (DEBUG) {
|
||||
Slog.v(TAG, "notifyWallpaperColorsChanged " + which);
|
||||
}
|
||||
|
||||
needsExtraction = wallpaper.primaryColors == null;
|
||||
}
|
||||
|
||||
// This should not be synchronized because color extraction
|
||||
// might take a while.
|
||||
if (needsExtraction) {
|
||||
extractColors(wallpaper);
|
||||
}
|
||||
|
||||
synchronized (mLock) {
|
||||
final int n = mColorsChangedListeners.beginBroadcast();
|
||||
for (int i = 0; i < n; i++) {
|
||||
IWallpaperManagerCallback callback = mColorsChangedListeners.getBroadcastItem(i);
|
||||
try {
|
||||
callback.onWallpaperColorsChanged(wallpaper.primaryColors, which);
|
||||
} catch (RemoteException e) {
|
||||
// Callback is gone, it's not necessary to unregister it since
|
||||
// RemoteCallbackList#getBroadcastItem will take care of it.
|
||||
}
|
||||
}
|
||||
mColorsChangedListeners.finishBroadcast();
|
||||
|
||||
final IWallpaperManagerCallback cb = mKeyguardListener;
|
||||
if (cb != null) {
|
||||
try {
|
||||
cb.onWallpaperColorsChanged(wallpaper.primaryColors, which);
|
||||
} catch (RemoteException e) {
|
||||
// Oh well it went away; no big deal
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void extractColors(WallpaperData wallpaper) {
|
||||
String cropFile = null;
|
||||
int wallpaperId = -1;
|
||||
synchronized (mLock) {
|
||||
// Only extract colors of ImageWallpaper or lock wallpapers (null)
|
||||
final boolean supportedComponent = mImageWallpaper.equals(wallpaper.wallpaperComponent)
|
||||
|| wallpaper.wallpaperComponent == null;
|
||||
if (!supportedComponent)
|
||||
return;
|
||||
|
||||
if (wallpaper.cropFile != null && wallpaper.cropFile.exists()) {
|
||||
cropFile = wallpaper.cropFile.getAbsolutePath();
|
||||
}
|
||||
wallpaperId = wallpaper.wallpaperId;
|
||||
}
|
||||
|
||||
if (cropFile != null) {
|
||||
final Bitmap bitmap = BitmapFactory.decodeFile(cropFile);
|
||||
if (bitmap == null) {
|
||||
Slog.w(TAG, "Cannot extract colors because wallpaper file could not be read.");
|
||||
return;
|
||||
}
|
||||
Palette palette = Palette.from(bitmap).generate();
|
||||
bitmap.recycle();
|
||||
|
||||
final List<Pair<Color, Integer>> colors = new ArrayList<>();
|
||||
for (Palette.Swatch swatch : palette.getSwatches()) {
|
||||
colors.add(new Pair<>(Color.valueOf(swatch.getRgb()),
|
||||
swatch.getPopulation()));
|
||||
}
|
||||
|
||||
synchronized (mLock) {
|
||||
if (wallpaper.wallpaperId == wallpaperId) {
|
||||
wallpaper.primaryColors = new WallpaperColors(colors);
|
||||
} else {
|
||||
Slog.w(TAG, "Not setting primary colors since wallpaper changed");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Once a new wallpaper has been written via setWallpaper(...), it needs to be cropped
|
||||
* for display.
|
||||
@@ -481,6 +580,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
|
||||
final IPackageManager mIPackageManager;
|
||||
final MyPackageMonitor mMonitor;
|
||||
final AppOpsManager mAppOpsManager;
|
||||
final RemoteCallbackList<IWallpaperManagerCallback> mColorsChangedListeners;
|
||||
WallpaperData mLastWallpaper;
|
||||
IWallpaperManagerCallback mKeyguardListener;
|
||||
boolean mWaitingForUnlock;
|
||||
@@ -557,6 +657,11 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
|
||||
*/
|
||||
int wallpaperId;
|
||||
|
||||
/**
|
||||
* Primary colors histogram
|
||||
*/
|
||||
WallpaperColors primaryColors;
|
||||
|
||||
WallpaperConnection connection;
|
||||
long lastDiedTime;
|
||||
boolean wallpaperUpdating;
|
||||
@@ -706,6 +811,35 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by a live wallpaper if its colors have changed.
|
||||
* @param primaryColors representation of wallpaper primary colors
|
||||
*/
|
||||
@Override
|
||||
public void onWallpaperColorsChanged(WallpaperColors primaryColors) {
|
||||
int which;
|
||||
synchronized (mLock) {
|
||||
// Do not broadcast changes on ImageWallpaper since it's handled
|
||||
// internally by this class.
|
||||
if (mImageWallpaper.equals(mWallpaper.wallpaperComponent)) {
|
||||
return;
|
||||
}
|
||||
|
||||
mWallpaper.primaryColors = primaryColors;
|
||||
|
||||
// Live wallpapers always are system wallpapers.
|
||||
which = FLAG_SYSTEM;
|
||||
// It's also the lock screen wallpaper when we don't have a bitmap in there
|
||||
WallpaperData lockedWallpaper = mLockWallpaperMap.get(mCurrentUserId);
|
||||
if (lockedWallpaper == null) {
|
||||
which |= FLAG_LOCK;
|
||||
}
|
||||
}
|
||||
if (which != 0) {
|
||||
notifyWallpaperColorsChanged(mWallpaper, which);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attachEngine(IWallpaperEngine engine) {
|
||||
synchronized (mLock) {
|
||||
@@ -916,6 +1050,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
|
||||
mMonitor.register(context, null, UserHandle.ALL, true);
|
||||
getWallpaperDir(UserHandle.USER_SYSTEM).mkdirs();
|
||||
loadSettingsLocked(UserHandle.USER_SYSTEM, false);
|
||||
mColorsChangedListeners = new RemoteCallbackList<>();
|
||||
}
|
||||
|
||||
private static File getWallpaperDir(int userId) {
|
||||
@@ -1130,6 +1265,10 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
|
||||
synchronized (mLock) {
|
||||
clearWallpaperLocked(false, which, userId, null);
|
||||
}
|
||||
|
||||
// When clearing a wallpaper, broadcast new valid colors
|
||||
WallpaperData data = getWallpaperSafeLocked(mCurrentUserId, which);
|
||||
notifyWallpaperColorsChanged(data, which);
|
||||
}
|
||||
|
||||
void clearWallpaperLocked(boolean defaultFailed, int which, int userId, IRemoteCallback reply) {
|
||||
@@ -1421,6 +1560,20 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerWallpaperColorsCallback(IWallpaperManagerCallback cb) {
|
||||
synchronized (mLock) {
|
||||
mColorsChangedListeners.register(cb);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterWallpaperColorsCallback(IWallpaperManagerCallback cb) {
|
||||
synchronized (mLock) {
|
||||
mColorsChangedListeners.unregister(cb);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setLockWallpaperCallback(IWallpaperManagerCallback cb) {
|
||||
checkPermission(android.Manifest.permission.INTERNAL_SYSTEM_WINDOW);
|
||||
@@ -1430,6 +1583,41 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WallpaperColors getWallpaperColors(int which) throws RemoteException {
|
||||
if (which != FLAG_LOCK && which != FLAG_SYSTEM) {
|
||||
throw new IllegalArgumentException("which should be either FLAG_LOCK or FLAG_SYSTEM");
|
||||
}
|
||||
|
||||
WallpaperData wallpaperData = null;
|
||||
boolean shouldExtract;
|
||||
|
||||
synchronized (mLock) {
|
||||
if (which == FLAG_LOCK) {
|
||||
wallpaperData = mLockWallpaperMap.get(mCurrentUserId);
|
||||
}
|
||||
|
||||
// Try to get the system wallpaper anyway since it might
|
||||
// also be the lock screen wallpaper
|
||||
if (wallpaperData == null) {
|
||||
wallpaperData = mWallpaperMap.get(mCurrentUserId);
|
||||
}
|
||||
|
||||
if (wallpaperData == null) {
|
||||
return null;
|
||||
}
|
||||
shouldExtract = wallpaperData.primaryColors == null;
|
||||
}
|
||||
|
||||
if (shouldExtract) {
|
||||
extractColors(wallpaperData);
|
||||
}
|
||||
|
||||
synchronized (mLock) {
|
||||
return wallpaperData.primaryColors;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParcelFileDescriptor setWallpaper(String name, String callingPackage,
|
||||
Rect cropHint, boolean allowBackup, Bundle extras, int which,
|
||||
@@ -1509,6 +1697,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
|
||||
lockWP.width = sysWP.width;
|
||||
lockWP.height = sysWP.height;
|
||||
lockWP.allowBackup = sysWP.allowBackup;
|
||||
lockWP.primaryColors = sysWP.primaryColors;
|
||||
|
||||
// Migrate the bitmap files outright; no need to copy
|
||||
try {
|
||||
@@ -1546,6 +1735,8 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
|
||||
if (extras != null) {
|
||||
extras.putInt(WallpaperManager.EXTRA_NEW_WALLPAPER_ID, wallpaper.wallpaperId);
|
||||
}
|
||||
// Nullify field to require new computation
|
||||
wallpaper.primaryColors = null;
|
||||
if (DEBUG) {
|
||||
Slog.v(TAG, "updateWallpaperBitmapLocked() : id=" + wallpaper.wallpaperId
|
||||
+ " name=" + name + " file=" + wallpaper.wallpaperFile.getName());
|
||||
@@ -1577,9 +1768,13 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
|
||||
false /* all */, true /* full */, "changing live wallpaper", null /* pkg */);
|
||||
checkPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT);
|
||||
|
||||
int which = FLAG_SYSTEM;
|
||||
boolean shouldNotifyColors = false;
|
||||
WallpaperData wallpaper;
|
||||
|
||||
synchronized (mLock) {
|
||||
if (DEBUG) Slog.v(TAG, "setWallpaperComponent name=" + name);
|
||||
WallpaperData wallpaper = mWallpaperMap.get(userId);
|
||||
wallpaper = mWallpaperMap.get(userId);
|
||||
if (wallpaper == null) {
|
||||
throw new IllegalStateException("Wallpaper not yet initialized for user " + userId);
|
||||
}
|
||||
@@ -1597,16 +1792,26 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
// New live wallpaper is also a lock wallpaper if nothing is set
|
||||
if (mLockWallpaperMap.get(userId) == null) {
|
||||
which |= FLAG_LOCK;
|
||||
}
|
||||
|
||||
try {
|
||||
wallpaper.imageWallpaperPending = false;
|
||||
if (bindWallpaperComponentLocked(name, false, true, wallpaper, null)) {
|
||||
wallpaper.wallpaperId = makeWallpaperIdLocked();
|
||||
notifyCallbacksLocked(wallpaper);
|
||||
shouldNotifyColors = true;
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldNotifyColors) {
|
||||
notifyWallpaperColorsChanged(wallpaper, which);
|
||||
}
|
||||
}
|
||||
|
||||
boolean bindWallpaperComponentLocked(ComponentName componentName, boolean force,
|
||||
@@ -1731,6 +1936,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
|
||||
}
|
||||
wallpaper.wallpaperComponent = componentName;
|
||||
wallpaper.connection = newConn;
|
||||
wallpaper.primaryColors = null;
|
||||
newConn.mReply = reply;
|
||||
try {
|
||||
if (wallpaper.userId == mCurrentUserId) {
|
||||
@@ -1810,6 +2016,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
|
||||
}
|
||||
}
|
||||
wallpaper.callbacks.finishBroadcast();
|
||||
|
||||
final Intent intent = new Intent(Intent.ACTION_WALLPAPER_CHANGED);
|
||||
mContext.sendBroadcastAsUser(intent, new UserHandle(mCurrentUserId));
|
||||
}
|
||||
@@ -1900,6 +2107,9 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
|
||||
|
||||
private void writeWallpaperAttributes(XmlSerializer out, String tag, WallpaperData wallpaper)
|
||||
throws IllegalArgumentException, IllegalStateException, IOException {
|
||||
if (DEBUG) {
|
||||
Slog.v(TAG, "writeWallpaperAttributes");
|
||||
}
|
||||
out.startTag(null, tag);
|
||||
out.attribute(null, "id", Integer.toString(wallpaper.wallpaperId));
|
||||
out.attribute(null, "width", Integer.toString(wallpaper.width));
|
||||
@@ -1923,6 +2133,20 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
|
||||
out.attribute(null, "paddingBottom", Integer.toString(wallpaper.padding.bottom));
|
||||
}
|
||||
|
||||
if (wallpaper.primaryColors != null) {
|
||||
int colorsCount = wallpaper.primaryColors.getColors().size();
|
||||
out.attribute(null, "colorsCount", Integer.toString(colorsCount));
|
||||
if (colorsCount > 0) {
|
||||
for (int i = 0; i < colorsCount; i++) {
|
||||
Pair<Color, Integer> wc = wallpaper.primaryColors.getColors().get(i);
|
||||
out.attribute(null, "colorValue"+i, Integer.toString(wc.first.toArgb()));
|
||||
out.attribute(null, "colorWeight"+i, Integer.toString(wc.second));
|
||||
}
|
||||
}
|
||||
out.attribute(null, "supportsDarkText",
|
||||
Integer.toString(wallpaper.primaryColors.supportsDarkText() ? 1 : 0));
|
||||
}
|
||||
|
||||
out.attribute(null, "name", wallpaper.name);
|
||||
if (wallpaper.wallpaperComponent != null
|
||||
&& !wallpaper.wallpaperComponent.equals(mImageWallpaper)) {
|
||||
@@ -2054,6 +2278,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
|
||||
Slog.v(TAG, "mWidth:" + wallpaper.width);
|
||||
Slog.v(TAG, "mHeight:" + wallpaper.height);
|
||||
Slog.v(TAG, "cropRect:" + wallpaper.cropHint);
|
||||
Slog.v(TAG, "primaryColors:" + wallpaper.primaryColors);
|
||||
Slog.v(TAG, "mName:" + wallpaper.name);
|
||||
Slog.v(TAG, "mNextWallpaperComponent:"
|
||||
+ wallpaper.nextWallpaperComponent);
|
||||
@@ -2152,6 +2377,18 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
|
||||
wallpaper.padding.top = getAttributeInt(parser, "paddingTop", 0);
|
||||
wallpaper.padding.right = getAttributeInt(parser, "paddingRight", 0);
|
||||
wallpaper.padding.bottom = getAttributeInt(parser, "paddingBottom", 0);
|
||||
int colorsCount = getAttributeInt(parser, "colorsCount", 0);
|
||||
if (colorsCount > 0) {
|
||||
List<Pair<Color, Integer>> colors = new ArrayList<>();
|
||||
for (int i = 0; i < colorsCount; i++) {
|
||||
colors.add(new Pair<>(
|
||||
Color.valueOf(getAttributeInt(parser, "colorValue"+i, 0)),
|
||||
getAttributeInt(parser, "colorWeight"+i, 0)
|
||||
));
|
||||
}
|
||||
boolean dark = getAttributeInt(parser, "supportsDarkText", 0) == 1;
|
||||
wallpaper.primaryColors = new WallpaperColors(colors, dark);
|
||||
}
|
||||
wallpaper.name = parser.getAttributeValue(null, "name");
|
||||
wallpaper.allowBackup = "true".equals(parser.getAttributeValue(null, "backup"));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user