Wallpaper Local color sampling
Test: Integration tests will be in a different CL Fixes: 173046221 Change-Id: I5755525f90f4c7445cbfd337057a34cfb1f3c4fe
This commit is contained in:
27
core/java/android/app/ILocalWallpaperColorConsumer.aidl
Normal file
27
core/java/android/app/ILocalWallpaperColorConsumer.aidl
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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;
|
||||
|
||||
import android.app.WallpaperColors;
|
||||
import android.graphics.RectF;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
oneway interface ILocalWallpaperColorConsumer {
|
||||
void onColorsChanged(in RectF area, in WallpaperColors colors);
|
||||
}
|
||||
@@ -17,9 +17,11 @@
|
||||
package android.app;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.os.Bundle;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.app.IWallpaperManagerCallback;
|
||||
import android.app.ILocalWallpaperColorConsumer;
|
||||
import android.app.WallpaperInfo;
|
||||
import android.content.ComponentName;
|
||||
import android.app.WallpaperColors;
|
||||
@@ -161,6 +163,18 @@ interface IWallpaperManager {
|
||||
*/
|
||||
WallpaperColors getWallpaperColors(int which, int userId, int displayId);
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
void removeOnLocalColorsChangedListener(
|
||||
in ILocalWallpaperColorConsumer callback, int which, int userId, int displayId);
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
void addOnLocalColorsChangedListener(in ILocalWallpaperColorConsumer callback,
|
||||
in List<RectF> regions, int which, int userId, int displayId);
|
||||
|
||||
/**
|
||||
* Register a callback to receive color updates from a display
|
||||
*/
|
||||
|
||||
@@ -66,6 +66,7 @@ import android.os.RemoteException;
|
||||
import android.os.StrictMode;
|
||||
import android.os.SystemProperties;
|
||||
import android.text.TextUtils;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import android.view.Display;
|
||||
@@ -107,6 +108,8 @@ public class WallpaperManager {
|
||||
private static boolean DEBUG = false;
|
||||
private float mWallpaperXStep = -1;
|
||||
private float mWallpaperYStep = -1;
|
||||
private static final @NonNull RectF LOCAL_COLOR_BOUNDS =
|
||||
new RectF(0, 0, 1, 1);
|
||||
|
||||
/** {@hide} */
|
||||
private static final String PROP_WALLPAPER = "ro.config.wallpaper";
|
||||
@@ -309,6 +312,8 @@ public class WallpaperManager {
|
||||
private int mCachedWallpaperUserId;
|
||||
private Bitmap mDefaultWallpaper;
|
||||
private Handler mMainLooperHandler;
|
||||
private ArrayMap<LocalWallpaperColorConsumer, ILocalWallpaperColorConsumer>
|
||||
mLocalColorCallbacks = new ArrayMap<>();
|
||||
|
||||
Globals(IWallpaperManager service, Looper looper) {
|
||||
mService = service;
|
||||
@@ -350,6 +355,40 @@ public class WallpaperManager {
|
||||
}
|
||||
}
|
||||
|
||||
private ILocalWallpaperColorConsumer wrap(LocalWallpaperColorConsumer callback) {
|
||||
ILocalWallpaperColorConsumer callback2 = new ILocalWallpaperColorConsumer.Stub() {
|
||||
@Override
|
||||
public void onColorsChanged(RectF area, WallpaperColors colors) {
|
||||
callback.onColorsChanged(area, colors);
|
||||
}
|
||||
};
|
||||
mLocalColorCallbacks.put(callback, callback2);
|
||||
return callback2;
|
||||
}
|
||||
|
||||
public void addOnColorsChangedListener(@NonNull LocalWallpaperColorConsumer callback,
|
||||
@NonNull List<RectF> regions, int which, int userId, int displayId) {
|
||||
try {
|
||||
mService.addOnLocalColorsChangedListener(wrap(callback) , regions, which,
|
||||
userId, displayId);
|
||||
} catch (RemoteException e) {
|
||||
// Can't get colors, connection lost.
|
||||
}
|
||||
}
|
||||
|
||||
public void removeOnColorsChangedListener(
|
||||
@NonNull LocalWallpaperColorConsumer callback, int which, int userId,
|
||||
int displayId) {
|
||||
ILocalWallpaperColorConsumer callback2 = mLocalColorCallbacks.remove(callback);
|
||||
if (callback2 == null) return;
|
||||
try {
|
||||
mService.removeOnLocalColorsChangedListener(
|
||||
callback2, which, userId, displayId);
|
||||
} catch (RemoteException e) {
|
||||
// Can't get colors, connection lost.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop listening to wallpaper color events.
|
||||
*
|
||||
@@ -1056,6 +1095,29 @@ public class WallpaperManager {
|
||||
return sGlobals.getWallpaperColors(which, userId, mContext.getDisplayId());
|
||||
}
|
||||
|
||||
/**
|
||||
* @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());
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public void removeOnColorsChangedListener(@NonNull LocalWallpaperColorConsumer callback) {
|
||||
sGlobals.removeOnColorsChangedListener(callback, FLAG_SYSTEM, mContext.getUserId(),
|
||||
mContext.getDisplayId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Version of {@link #getWallpaperFile(int)} that can access the wallpaper data
|
||||
* for a given user. The caller must hold the INTERACT_ACROSS_USERS_FULL
|
||||
@@ -2202,4 +2264,18 @@ public class WallpaperManager {
|
||||
onColorsChanged(colors, which);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback to update a consumer with a local color change
|
||||
* @hide
|
||||
*/
|
||||
public interface LocalWallpaperColorConsumer {
|
||||
|
||||
/**
|
||||
* Gets called when a color of an area gets updated
|
||||
* @param area
|
||||
* @param colors
|
||||
*/
|
||||
void onColorsChanged(RectF area, WallpaperColors colors);
|
||||
}
|
||||
}
|
||||
|
||||
96
core/java/android/service/wallpaper/EngineWindowPage.java
Normal file
96
core/java/android/service/wallpaper/EngineWindowPage.java
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.service.wallpaper;
|
||||
|
||||
import android.app.WallpaperColors;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.RectF;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* This class represents a page of a launcher page used by the wallpaper
|
||||
* @hide
|
||||
*/
|
||||
public class EngineWindowPage {
|
||||
private Bitmap mScreenShot;
|
||||
private volatile long mLastUpdateTime;
|
||||
private Set<RectF> mCallbackAreas = new ArraySet<>();
|
||||
private Map<RectF, WallpaperColors> mRectFColors = new ArrayMap<>();
|
||||
|
||||
/** should be locked extrnally */
|
||||
public void addArea(RectF area) {
|
||||
mCallbackAreas.add(area);
|
||||
}
|
||||
|
||||
/** should be locked extrnally */
|
||||
public void addWallpaperColors(RectF area, WallpaperColors colors) {
|
||||
mCallbackAreas.add(area);
|
||||
mRectFColors.put(area, colors);
|
||||
}
|
||||
|
||||
/** get screenshot bitmap */
|
||||
public Bitmap getBitmap() {
|
||||
if (mScreenShot == null || mScreenShot.isRecycled()) return null;
|
||||
return mScreenShot;
|
||||
}
|
||||
|
||||
/** remove callbacks for an area */
|
||||
public void removeArea(RectF area) {
|
||||
mCallbackAreas.remove(area);
|
||||
mRectFColors.remove(area);
|
||||
}
|
||||
|
||||
/** set the last time the screenshot was updated */
|
||||
public void setLastUpdateTime(long lastUpdateTime) {
|
||||
mLastUpdateTime = lastUpdateTime;
|
||||
}
|
||||
|
||||
/** get last screenshot time */
|
||||
public long getLastUpdateTime() {
|
||||
return mLastUpdateTime;
|
||||
}
|
||||
|
||||
/** get colors for an area */
|
||||
public WallpaperColors getColors(RectF rect) {
|
||||
return mRectFColors.get(rect);
|
||||
}
|
||||
|
||||
/** set the new bitmap version */
|
||||
public void setBitmap(Bitmap screenShot) {
|
||||
mScreenShot = screenShot;
|
||||
}
|
||||
|
||||
/** get areas of interest */
|
||||
public Set<RectF> getAreas() {
|
||||
return mCallbackAreas;
|
||||
}
|
||||
|
||||
/** run operations on this page */
|
||||
public synchronized void execSync(Consumer<EngineWindowPage> run) {
|
||||
run.accept(this);
|
||||
}
|
||||
|
||||
/** nullify the area color */
|
||||
public void removeColor(RectF colorArea) {
|
||||
mRectFColors.remove(colorArea);
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package android.service.wallpaper;
|
||||
|
||||
import android.graphics.RectF;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.service.wallpaper.IWallpaperEngine;
|
||||
import android.app.WallpaperColors;
|
||||
@@ -28,4 +29,5 @@ interface IWallpaperConnection {
|
||||
void engineShown(IWallpaperEngine engine);
|
||||
ParcelFileDescriptor setWallpaper(String name);
|
||||
void onWallpaperColorsChanged(in WallpaperColors colors, int displayId);
|
||||
void onLocalWallpaperColorsChanged(in RectF area, in WallpaperColors colors, int displayId);
|
||||
}
|
||||
|
||||
@@ -16,7 +16,10 @@
|
||||
|
||||
package android.service.wallpaper;
|
||||
|
||||
import android.app.ILocalWallpaperColorConsumer;
|
||||
import android.app.WallpaperColors;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.view.MotionEvent;
|
||||
import android.os.Bundle;
|
||||
|
||||
@@ -39,4 +42,6 @@ oneway interface IWallpaperEngine {
|
||||
void destroy();
|
||||
void setZoomOut(float scale);
|
||||
void scalePreview(in Rect positionInWindow);
|
||||
void removeLocalColorsAreas(in List<RectF> regions);
|
||||
void addLocalColorsAreas(in List<RectF> regions);
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import static android.graphics.Matrix.MSKEW_Y;
|
||||
import static android.view.View.SYSTEM_UI_FLAG_VISIBLE;
|
||||
|
||||
import android.annotation.FloatRange;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SdkConstant;
|
||||
import android.annotation.SdkConstant.SdkConstantType;
|
||||
@@ -42,6 +43,7 @@ import android.graphics.Matrix;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.hardware.display.DisplayManager;
|
||||
import android.hardware.display.DisplayManager.DisplayListener;
|
||||
@@ -53,6 +55,8 @@ import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SystemClock;
|
||||
import android.os.Trace;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
import android.util.MergedConfiguration;
|
||||
import android.view.Display;
|
||||
@@ -66,6 +70,8 @@ import android.view.InputEventReceiver;
|
||||
import android.view.InsetsSourceControl;
|
||||
import android.view.InsetsState;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.PixelCopy;
|
||||
import android.view.Surface;
|
||||
import android.view.SurfaceControl;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.View;
|
||||
@@ -83,7 +89,10 @@ import com.android.internal.view.BaseSurfaceHolder;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
@@ -115,7 +124,12 @@ public abstract class WallpaperService extends Service {
|
||||
public static final String SERVICE_META_DATA = "android.service.wallpaper";
|
||||
|
||||
static final String TAG = "WallpaperService";
|
||||
static final boolean DEBUG = false;
|
||||
static final boolean DEBUG = true;
|
||||
static final float MIN_PAGE_ALLOWED_MARGIN = .05f;
|
||||
private static final int MIN_BITMAP_SCREENSHOT_WIDTH = 64;
|
||||
private static final long DEFAULT_UPDATE_SCREENSHOT_DURATION = 60 * 1000; //Once per minute
|
||||
private static final @NonNull RectF LOCAL_COLOR_BOUNDS =
|
||||
new RectF(0, 0, 1, 1);
|
||||
|
||||
private static final int DO_ATTACH = 10;
|
||||
private static final int DO_DETACH = 20;
|
||||
@@ -134,6 +148,8 @@ public abstract class WallpaperService extends Service {
|
||||
private static final int MSG_REQUEST_WALLPAPER_COLORS = 10050;
|
||||
private static final int MSG_ZOOM = 10100;
|
||||
private static final int MSG_SCALE_PREVIEW = 10110;
|
||||
private static final List<Float> PROHIBITED_STEPS = Arrays.asList(0f, Float.POSITIVE_INFINITY,
|
||||
Float.NEGATIVE_INFINITY);
|
||||
|
||||
private static final int NOTIFY_COLORS_RATE_LIMIT_MS = 1000;
|
||||
|
||||
@@ -158,6 +174,14 @@ public abstract class WallpaperService extends Service {
|
||||
*/
|
||||
public class Engine {
|
||||
IWallpaperEngineWrapper mIWallpaperEngine;
|
||||
final ArraySet<RectF> mLocalColorAreas = new ArraySet<>(4);
|
||||
final ArraySet<RectF> mLocalColorsToAdd = new ArraySet<>(4);
|
||||
|
||||
// 2D matrix [x][y] to represent a page of a portion of a window
|
||||
EngineWindowPage[] mWindowPages = new EngineWindowPage[1];
|
||||
Bitmap mLastScreenshot;
|
||||
int mLastWindowPage = -1;
|
||||
float mLastPageOffset = 0;
|
||||
|
||||
// Copies from mIWallpaperEngine.
|
||||
HandlerCaller mCaller;
|
||||
@@ -409,8 +433,8 @@ public abstract class WallpaperService extends Service {
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public Engine(Supplier<Long> clockFunction, Handler handler) {
|
||||
mClockFunction = clockFunction;
|
||||
mHandler = handler;
|
||||
mClockFunction = clockFunction;
|
||||
mHandler = handler;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -447,6 +471,19 @@ public abstract class WallpaperService extends Service {
|
||||
return mReportedVisible;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the wallpaper is capable of extracting local colors in a rectangle area,
|
||||
* Must implement without calling super:
|
||||
* {@link #addLocalColorsAreas(List)}
|
||||
* {@link #removeLocalColorsAreas(List)}
|
||||
* When local colors change, call {@link #notifyLocalColorsChanged(List, List)}
|
||||
* See {@link com.android.systemui.ImageWallpaper} for an example
|
||||
* @hide
|
||||
*/
|
||||
public boolean supportsLocalColorExtraction() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this engine is running in preview mode -- that is,
|
||||
* it is being shown to the user before they select it as the actual
|
||||
@@ -691,6 +728,8 @@ public abstract class WallpaperService extends Service {
|
||||
Log.w(TAG, "Can't notify system because wallpaper connection "
|
||||
+ "was not established.");
|
||||
}
|
||||
resetWindowPages();
|
||||
processLocalColors(mPendingXOffset, mPendingXOffsetStep);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Can't notify system because wallpaper connection was lost.", e);
|
||||
}
|
||||
@@ -713,6 +752,28 @@ public abstract class WallpaperService extends Service {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the changed local color areas for the connection
|
||||
* @param regions
|
||||
* @param colors
|
||||
* @hide
|
||||
*/
|
||||
public void notifyLocalColorsChanged(@NonNull List<RectF> regions,
|
||||
@NonNull List<WallpaperColors> colors)
|
||||
throws RuntimeException {
|
||||
for (int i = 0; i < regions.size() && i < colors.size() && colors.get(i) != null; i++) {
|
||||
try {
|
||||
mConnection.onLocalWallpaperColorsChanged(
|
||||
regions.get(i),
|
||||
colors.get(i),
|
||||
mDisplayContext.getDisplayId()
|
||||
);
|
||||
} catch (RemoteException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets internal engine state. Only for testing.
|
||||
* @param created {@code true} or {@code false}.
|
||||
@@ -1068,7 +1129,9 @@ public abstract class WallpaperService extends Service {
|
||||
mIsCreating = false;
|
||||
mSurfaceCreated = true;
|
||||
if (redrawNeeded) {
|
||||
resetWindowPages();
|
||||
mSession.finishDrawing(mWindow, null /* postDrawTransaction */);
|
||||
processLocalColors(mPendingXOffset, mPendingXOffsetStep);
|
||||
}
|
||||
reposition();
|
||||
mIWallpaperEngine.reportShown();
|
||||
@@ -1209,6 +1272,7 @@ public abstract class WallpaperService extends Service {
|
||||
if (!mDestroyed) {
|
||||
mVisible = visible;
|
||||
reportVisibility();
|
||||
if (visible) processLocalColors(mPendingXOffset, mPendingXOffsetStep);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1278,6 +1342,405 @@ public abstract class WallpaperService extends Service {
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
|
||||
// setup local color extraction data
|
||||
processLocalColors(xOffset, xOffsetStep);
|
||||
}
|
||||
|
||||
private void processLocalColors(float xOffset, float xOffsetStep) {
|
||||
// implemented by the wallpaper
|
||||
if (supportsLocalColorExtraction()) return;
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "processLocalColors " + xOffset + " of step "
|
||||
+ xOffsetStep);
|
||||
}
|
||||
//below is the default implementation
|
||||
if (!validStep(xOffsetStep)) {
|
||||
if (DEBUG) {
|
||||
Log.w(TAG, "invalid offset step " + xOffsetStep);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int xPage = Math.round(xOffset / xOffsetStep);
|
||||
if (!shouldProcessPage(xPage, xOffset, xOffsetStep)) return;
|
||||
mLastWindowPage = xPage;
|
||||
mLastPageOffset = xOffset;
|
||||
int xPages = Math.round(1 / xOffsetStep);
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "xPages " + xPages + " xPage " + xPage);
|
||||
Log.d(TAG, "xOffsetStep " + xOffsetStep + " xOffset " + xOffset);
|
||||
}
|
||||
EngineWindowPage current;
|
||||
synchronized (mLock) {
|
||||
if (mWindowPages.length == 0 || (mWindowPages.length != xPages)) {
|
||||
mWindowPages = new EngineWindowPage[xPages];
|
||||
initWindowPages(mWindowPages, xOffsetStep);
|
||||
}
|
||||
if (mLocalColorsToAdd.size() != 0) {
|
||||
for (RectF colorArea : mLocalColorsToAdd) {
|
||||
if (!isValid(colorArea)) continue;
|
||||
mLocalColorAreas.add(colorArea);
|
||||
int colorPage = getRectFPage(colorArea, xOffsetStep);
|
||||
EngineWindowPage currentPage = mWindowPages[colorPage];
|
||||
if (currentPage == null) {
|
||||
currentPage = new EngineWindowPage();
|
||||
currentPage.addArea(colorArea);
|
||||
mWindowPages[colorPage] = currentPage;
|
||||
} else {
|
||||
currentPage.setLastUpdateTime(0);
|
||||
currentPage.removeColor(colorArea);
|
||||
}
|
||||
}
|
||||
mLocalColorsToAdd.clear();
|
||||
}
|
||||
if (xPage >= mWindowPages.length) {
|
||||
if (DEBUG) {
|
||||
Log.e(TAG, "error xPage >= mWindowPages.length page: " + xPage);
|
||||
Log.e(TAG, "error on page " + xPage + " out of " + xPages);
|
||||
Log.e(TAG,
|
||||
"error on xOffsetStep " + xOffsetStep + " xOffset " + xOffset);
|
||||
}
|
||||
xPage = mWindowPages.length - 1;
|
||||
}
|
||||
current = mWindowPages[xPage];
|
||||
if (current == null) {
|
||||
if (DEBUG) Log.d(TAG, "making page " + xPage + " out of " + xPages);
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "xOffsetStep " + xOffsetStep + " xOffset " + xOffset);
|
||||
}
|
||||
current = new EngineWindowPage();
|
||||
mWindowPages[xPage] = current;
|
||||
}
|
||||
}
|
||||
updatePage(current, xPage, xPages, xOffsetStep);
|
||||
}
|
||||
|
||||
private boolean shouldProcessPage(int xPage, float xOffset, float xOffsetStep) {
|
||||
float pageCenter = xOffsetStep * xPage + xOffsetStep / 2;
|
||||
|
||||
return (pageCenter > xOffset && pageCenter < mLastPageOffset)
|
||||
|| (pageCenter < xOffset && pageCenter > mLastPageOffset);
|
||||
}
|
||||
|
||||
private void initWindowPages(EngineWindowPage[] windowPages, float step) {
|
||||
for (int i = 0; i < windowPages.length; i++) {
|
||||
windowPages[i] = new EngineWindowPage();
|
||||
}
|
||||
mLocalColorAreas.addAll(mLocalColorsToAdd);
|
||||
mLocalColorsToAdd.clear();
|
||||
for (RectF area: mLocalColorAreas) {
|
||||
if (!isValid(area)) {
|
||||
mLocalColorAreas.remove(area);
|
||||
continue;
|
||||
}
|
||||
int pageNum = getRectFPage(area, step);
|
||||
windowPages[pageNum].addArea(area);
|
||||
}
|
||||
}
|
||||
|
||||
void updatePage(EngineWindowPage currentPage, int pageIndx, int numPages,
|
||||
float xOffsetStep) {
|
||||
// to save creating a runnable, check twice
|
||||
long current = System.nanoTime() / 1_000_000;
|
||||
AtomicLong lapsed = new AtomicLong(current - currentPage.getLastUpdateTime());
|
||||
if (lapsed.get() < DEFAULT_UPDATE_SCREENSHOT_DURATION) return;
|
||||
currentPage.execSync((page) -> {
|
||||
// just in case of race double check
|
||||
long currentInner = System.nanoTime() / 1_000_000;
|
||||
lapsed.set(currentInner - page.getLastUpdateTime());
|
||||
page.setLastUpdateTime(currentInner);
|
||||
});
|
||||
long lastUpdate = currentPage.getLastUpdateTime();
|
||||
if (lapsed.get() < DEFAULT_UPDATE_SCREENSHOT_DURATION) return;
|
||||
Surface surface = mSurfaceHolder.getSurface();
|
||||
boolean widthIsLarger =
|
||||
mSurfaceControl.getWidth() > mSurfaceControl.getHeight();
|
||||
int smaller = widthIsLarger ? mSurfaceControl.getWidth()
|
||||
: mSurfaceControl.getHeight();
|
||||
float ratio = (float) MIN_BITMAP_SCREENSHOT_WIDTH / (float) smaller;
|
||||
int width = (int) (ratio * mSurfaceControl.getWidth());
|
||||
int height = (int) (ratio * mSurfaceControl.getHeight());
|
||||
if (width <= 0 || height <= 0) {
|
||||
return;
|
||||
}
|
||||
Bitmap screenShot = Bitmap.createBitmap(width, height,
|
||||
Bitmap.Config.ARGB_8888);
|
||||
final Bitmap finalScreenShot = screenShot;
|
||||
Trace.beginSection("WallpaperService#pixelCopy");
|
||||
PixelCopy.request(surface, screenShot, (res) -> {
|
||||
Trace.endSection();
|
||||
if (DEBUG) Log.d(TAG, "result of pixel copy is " + res);
|
||||
if (res != PixelCopy.SUCCESS) {
|
||||
currentPage.execSync((p) -> {
|
||||
// reset the time
|
||||
p.setLastUpdateTime(lastUpdate);
|
||||
// assign the last bitmap taken for now
|
||||
p.setBitmap(mLastScreenshot);
|
||||
});
|
||||
return;
|
||||
}
|
||||
mLastScreenshot = finalScreenShot;
|
||||
// going to hold this lock for a while
|
||||
currentPage.execSync((p) -> {
|
||||
p.setBitmap(finalScreenShot);
|
||||
});
|
||||
updatePageColors(currentPage, pageIndx, numPages, xOffsetStep);
|
||||
}, mHandler);
|
||||
|
||||
}
|
||||
// locked by the passed page
|
||||
private void updatePageColors(EngineWindowPage page, int pageIndx, int numPages,
|
||||
float xOffsetStep) {
|
||||
if (page.getBitmap() == null) return;
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "updatePageColorsLocked for page " + pageIndx + " with areas "
|
||||
+ page.getAreas().size() + " and bitmap size of "
|
||||
+ page.getBitmap().getWidth() + " x " + page.getBitmap().getHeight());
|
||||
}
|
||||
for (RectF area: page.getAreas()) {
|
||||
RectF subArea = generateSubRect(area, pageIndx, numPages);
|
||||
Bitmap b = page.getBitmap();
|
||||
int x = Math.round(b.getWidth() * subArea.left);
|
||||
int y = Math.round(b.getHeight() * subArea.top);
|
||||
int width = Math.round(b.getWidth() * subArea.width());
|
||||
int height = Math.round(b.getHeight() * subArea.height());
|
||||
Bitmap target;
|
||||
try {
|
||||
target = Bitmap.createBitmap(page.getBitmap(), x, y, width, height);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error creating page local color bitmap", e);
|
||||
continue;
|
||||
}
|
||||
WallpaperColors color = WallpaperColors.fromBitmap(target);
|
||||
target.recycle();
|
||||
WallpaperColors currentColor = page.getColors(area);
|
||||
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "getting local bitmap area x " + x + " y " + y
|
||||
+ " width " + width + " height " + height + " for sub area " + subArea
|
||||
+ " and with page " + pageIndx + " of " + numPages);
|
||||
|
||||
}
|
||||
if (currentColor == null || !color.equals(currentColor)) {
|
||||
page.addWallpaperColors(area, color);
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "onLocalWallpaperColorsChanged"
|
||||
+ " local color callback for area" + area + " for page " + pageIndx
|
||||
+ " of " + numPages);
|
||||
}
|
||||
try {
|
||||
mConnection.onLocalWallpaperColorsChanged(area, color,
|
||||
mDisplayContext.getDisplayId());
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Error calling Connection.onLocalWallpaperColorsChanged", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private RectF generateSubRect(RectF in, int pageInx, int numPages) {
|
||||
float minLeft = (float) (pageInx) / (float) (numPages);
|
||||
float maxRight = (float) (pageInx + 1) / (float) (numPages);
|
||||
float left = in.left;
|
||||
float right = in.right;
|
||||
|
||||
// bound rect
|
||||
if (left < minLeft) left = minLeft;
|
||||
if (right > maxRight) right = maxRight;
|
||||
|
||||
// scale up the sub area then trim
|
||||
left = (left * (float) numPages) % 1f;
|
||||
right = (right * (float) numPages) % 1f;
|
||||
if (right == 0f) {
|
||||
right = 1f;
|
||||
}
|
||||
|
||||
return new RectF(left, in.top, right, in.bottom);
|
||||
}
|
||||
|
||||
private void resetWindowPages() {
|
||||
if (supportsLocalColorExtraction()) return;
|
||||
mLastWindowPage = -1;
|
||||
synchronized (mLock) {
|
||||
for (int i = 0; i < mWindowPages.length; i++) {
|
||||
EngineWindowPage page = mWindowPages[i];
|
||||
if (page != null) {
|
||||
page.execSync((p) -> {
|
||||
p.setLastUpdateTime(0L);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int getRectFPage(RectF area, float step) {
|
||||
if (!isValid(area)) return 0;
|
||||
if (!validStep(step)) return 0;
|
||||
int pages = Math.round(1 / step);
|
||||
int page = Math.round(area.centerX() * pages);
|
||||
if (page == pages) return pages - 1;
|
||||
if (page == mWindowPages.length) page = mWindowPages.length - 1;
|
||||
return page;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add local colors areas of interest
|
||||
* @param regions list of areas
|
||||
* @hide
|
||||
*/
|
||||
public void addLocalColorsAreas(@NonNull List<RectF> regions) {
|
||||
if (supportsLocalColorExtraction()) return;
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "addLocalColorsAreas adding local color areas " + regions);
|
||||
}
|
||||
float step = mPendingXOffsetStep;
|
||||
|
||||
List<WallpaperColors> colors = getLocalWallpaperColors(regions);
|
||||
synchronized (mLock) {
|
||||
if (!validStep(step)) {
|
||||
mLocalColorsToAdd.addAll(regions);
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < regions.size(); i++) {
|
||||
RectF area = regions.get(i);
|
||||
if (!isValid(area)) continue;
|
||||
int pageInx = getRectFPage(area, step);
|
||||
// no page should be null
|
||||
EngineWindowPage page = mWindowPages[pageInx];
|
||||
|
||||
if (page != null) {
|
||||
mLocalColorAreas.add(area);
|
||||
page.addArea(area);
|
||||
WallpaperColors color = colors.get(i);
|
||||
if (color != null && !color.equals(page.getColors(area))) {
|
||||
page.execSync(p -> {
|
||||
p.addWallpaperColors(area, color);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
mLocalColorsToAdd.add(area);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < colors.size() && colors.get(i) != null; i++) {
|
||||
try {
|
||||
mConnection.onLocalWallpaperColorsChanged(regions.get(i), colors.get(i),
|
||||
mDisplayContext.getDisplayId());
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Error calling Connection.onLocalWallpaperColorsChanged", e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove local colors areas of interest if they exist
|
||||
* @param regions list of areas
|
||||
* @hide
|
||||
*/
|
||||
public void removeLocalColorsAreas(@NonNull List<RectF> regions) {
|
||||
if (supportsLocalColorExtraction()) return;
|
||||
synchronized (mLock) {
|
||||
float step = mPendingXOffsetStep;
|
||||
mLocalColorsToAdd.removeAll(regions);
|
||||
mLocalColorAreas.removeAll(regions);
|
||||
if (!validStep(step)) {
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < regions.size(); i++) {
|
||||
RectF area = regions.get(i);
|
||||
if (!isValid(area)) continue;
|
||||
int pageInx = getRectFPage(area, step);
|
||||
// no page should be null
|
||||
EngineWindowPage page = mWindowPages[pageInx];
|
||||
if (page != null) {
|
||||
page.execSync(p -> {
|
||||
p.removeArea(area);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private @NonNull List<WallpaperColors> getLocalWallpaperColors(@NonNull List<RectF> areas) {
|
||||
ArrayList<WallpaperColors> colors = new ArrayList<>(areas.size());
|
||||
float step = mPendingXOffsetStep;
|
||||
if (!validStep(step)) {
|
||||
if (DEBUG) Log.d(TAG, "invalid step size " + step);
|
||||
step = 1.0f;
|
||||
}
|
||||
for (int i = 0; i < areas.size(); i++) {
|
||||
RectF currentArea = areas.get(i);
|
||||
EngineWindowPage page;
|
||||
RectF area;
|
||||
int pageIndx;
|
||||
synchronized (mLock) {
|
||||
pageIndx = getRectFPage(currentArea, step);
|
||||
if (mWindowPages.length == 0 || pageIndx < 0
|
||||
|| pageIndx > mWindowPages.length || !isValid(currentArea)) {
|
||||
colors.add(null);
|
||||
continue;
|
||||
}
|
||||
area = generateSubRect(currentArea, pageIndx, mWindowPages.length);
|
||||
page = mWindowPages[pageIndx];
|
||||
}
|
||||
if (page == null) {
|
||||
colors.add(null);
|
||||
continue;
|
||||
}
|
||||
float finalStep = step;
|
||||
int finalPageIndx = pageIndx;
|
||||
Bitmap screenShot = page.getBitmap();
|
||||
if (screenShot == null || screenShot.isRecycled()) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "invalid bitmap " + screenShot
|
||||
+ " for page " + finalPageIndx);
|
||||
}
|
||||
page.setLastUpdateTime(0);
|
||||
colors.add(null);
|
||||
continue;
|
||||
}
|
||||
Bitmap b = screenShot;
|
||||
Rect subImage = new Rect(
|
||||
Math.round(area.left * b.getWidth() / finalStep),
|
||||
Math.round(area.top * b.getHeight()),
|
||||
Math.round(area.right * b.getWidth() / finalStep),
|
||||
Math.round(area.bottom * b.getHeight())
|
||||
);
|
||||
subImage = fixRect(b, subImage);
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "getting subbitmap of " + subImage.toString()
|
||||
+ " for RectF " + area.toString()
|
||||
+ " screenshot width " + screenShot.getWidth() + " height "
|
||||
+ screenShot.getHeight());
|
||||
}
|
||||
Bitmap colorImg = Bitmap.createBitmap(screenShot,
|
||||
subImage.left, subImage.top, subImage.width(), subImage.height());
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "created bitmap " + colorImg.getWidth() + ", "
|
||||
+ colorImg.getHeight());
|
||||
}
|
||||
WallpaperColors color = WallpaperColors.fromBitmap(colorImg);
|
||||
colors.add(color);
|
||||
}
|
||||
return colors;
|
||||
}
|
||||
|
||||
// fix the rect to be included within the bounds of the bitmap
|
||||
private Rect fixRect(Bitmap b, Rect r) {
|
||||
r.left = r.left >= r.right || r.left >= b.getWidth() || r.left > 0
|
||||
? 0
|
||||
: r.left;
|
||||
r.right = r.left >= r.right || r.right > b.getWidth()
|
||||
? b.getWidth()
|
||||
: r.right;
|
||||
return r;
|
||||
}
|
||||
|
||||
private boolean validStep(float step) {
|
||||
return !PROHIBITED_STEPS.contains(step) && step > 0. && step <= 1.;
|
||||
}
|
||||
|
||||
void doCommand(WallpaperCommand cmd) {
|
||||
@@ -1371,6 +1834,16 @@ public abstract class WallpaperService extends Service {
|
||||
};
|
||||
}
|
||||
|
||||
private boolean isValid(RectF area) {
|
||||
boolean valid = area.bottom > area.top && area.left < area.right
|
||||
&& LOCAL_COLOR_BOUNDS.contains(area);
|
||||
return valid;
|
||||
}
|
||||
|
||||
private boolean inRectFRange(float number) {
|
||||
return number >= 0f && number <= 1f;
|
||||
}
|
||||
|
||||
class IWallpaperEngineWrapper extends IWallpaperEngine.Stub
|
||||
implements HandlerCaller.Callback {
|
||||
private final HandlerCaller mCaller;
|
||||
@@ -1477,6 +1950,14 @@ public abstract class WallpaperService extends Service {
|
||||
mCaller.sendMessage(msg);
|
||||
}
|
||||
|
||||
public void addLocalColorsAreas(List<RectF> regions) {
|
||||
mEngine.addLocalColorsAreas(regions);
|
||||
}
|
||||
|
||||
public void removeLocalColorsAreas(List<RectF> regions) {
|
||||
mEngine.removeLocalColorsAreas(regions);
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
Message msg = mCaller.obtainMessage(DO_DETACH);
|
||||
mCaller.sendMessage(msg);
|
||||
@@ -1516,14 +1997,15 @@ public abstract class WallpaperService extends Service {
|
||||
}
|
||||
switch (message.what) {
|
||||
case DO_ATTACH: {
|
||||
Engine engine = onCreateEngine();
|
||||
mEngine = engine;
|
||||
try {
|
||||
mConnection.attachEngine(this, mDisplayId);
|
||||
} catch (RemoteException e) {
|
||||
engine.detach();
|
||||
Log.w(TAG, "Wallpaper host disappeared", e);
|
||||
return;
|
||||
}
|
||||
Engine engine = onCreateEngine();
|
||||
mEngine = engine;
|
||||
mActiveEngines.add(engine);
|
||||
engine.attach(this);
|
||||
return;
|
||||
|
||||
@@ -16,7 +16,10 @@
|
||||
|
||||
package com.android.systemui;
|
||||
|
||||
import android.app.WallpaperColors;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.SystemClock;
|
||||
@@ -26,13 +29,16 @@ import android.util.Log;
|
||||
import android.util.Size;
|
||||
import android.view.SurfaceHolder;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.systemui.glwallpaper.EglHelper;
|
||||
import com.android.systemui.glwallpaper.GLWallpaperRenderer;
|
||||
import com.android.systemui.glwallpaper.ImageWallpaperRenderer;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
@@ -45,8 +51,13 @@ public class ImageWallpaper extends WallpaperService {
|
||||
// We delayed destroy render context that subsequent render requests have chance to cancel it.
|
||||
// This is to avoid destroying then recreating render context in a very short time.
|
||||
private static final int DELAY_FINISH_RENDERING = 1000;
|
||||
private static final @android.annotation.NonNull RectF LOCAL_COLOR_BOUNDS =
|
||||
new RectF(0, 0, 1, 1);
|
||||
private static final boolean DEBUG = false;
|
||||
private ArrayList<RectF> mLocalColorsToAdd = new ArrayList<>();
|
||||
private HandlerThread mWorker;
|
||||
// scaled down version
|
||||
private Bitmap mMiniBitmap;
|
||||
|
||||
@Inject
|
||||
public ImageWallpaper() {
|
||||
@@ -70,6 +81,7 @@ public class ImageWallpaper extends WallpaperService {
|
||||
super.onDestroy();
|
||||
mWorker.quitSafely();
|
||||
mWorker = null;
|
||||
mMiniBitmap = null;
|
||||
}
|
||||
|
||||
class GLEngine extends Engine {
|
||||
@@ -80,7 +92,7 @@ public class ImageWallpaper extends WallpaperService {
|
||||
@VisibleForTesting
|
||||
static final int MIN_SURFACE_HEIGHT = 64;
|
||||
|
||||
private GLWallpaperRenderer mRenderer;
|
||||
private ImageWallpaperRenderer mRenderer;
|
||||
private EglHelper mEglHelper;
|
||||
private final Runnable mFinishRenderingTask = this::finishRendering;
|
||||
private boolean mNeedRedraw;
|
||||
@@ -101,6 +113,12 @@ public class ImageWallpaper extends WallpaperService {
|
||||
setFixedSizeAllowed(true);
|
||||
setOffsetNotificationsEnabled(false);
|
||||
updateSurfaceSize();
|
||||
mMiniBitmap = null;
|
||||
if (mWorker == null || mWorker.getThreadHandler() == null) {
|
||||
updateMiniBitmap();
|
||||
} else {
|
||||
mWorker.getThreadHandler().post(this::updateMiniBitmap);
|
||||
}
|
||||
}
|
||||
|
||||
EglHelper getEglHelperInstance() {
|
||||
@@ -111,6 +129,20 @@ public class ImageWallpaper extends WallpaperService {
|
||||
return new ImageWallpaperRenderer(getDisplayContext());
|
||||
}
|
||||
|
||||
private void updateMiniBitmap() {
|
||||
mRenderer.useBitmap(b -> {
|
||||
int size = Math.min(b.getWidth(), b.getHeight());
|
||||
float scale = 1.0f;
|
||||
if (size > MIN_SURFACE_WIDTH) {
|
||||
scale = (float) MIN_SURFACE_WIDTH / (float) size;
|
||||
}
|
||||
mMiniBitmap = Bitmap.createScaledBitmap(b, Math.round(scale * b.getWidth()),
|
||||
Math.round(scale * b.getHeight()), false);
|
||||
computeAndNotifyLocalColors(mLocalColorsToAdd, mMiniBitmap);
|
||||
mLocalColorsToAdd.clear();
|
||||
});
|
||||
}
|
||||
|
||||
private void updateSurfaceSize() {
|
||||
SurfaceHolder holder = getSurfaceHolder();
|
||||
Size frameSize = mRenderer.reportSurfaceSize();
|
||||
@@ -126,6 +158,7 @@ public class ImageWallpaper extends WallpaperService {
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
mMiniBitmap = null;
|
||||
mWorker.getThreadHandler().post(() -> {
|
||||
mRenderer.finish();
|
||||
mRenderer = null;
|
||||
@@ -134,6 +167,61 @@ public class ImageWallpaper extends WallpaperService {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public boolean supportsLocalColorExtraction() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addLocalColorsAreas(@NonNull List<RectF> regions) {
|
||||
mWorker.getThreadHandler().post(() -> {
|
||||
Bitmap bitmap = mMiniBitmap;
|
||||
if (bitmap == null) {
|
||||
mLocalColorsToAdd.addAll(regions);
|
||||
} else {
|
||||
computeAndNotifyLocalColors(regions, bitmap);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void computeAndNotifyLocalColors(@NonNull List<RectF> regions, Bitmap b) {
|
||||
List<WallpaperColors> colors = getLocalWallpaperColors(regions, b);
|
||||
try {
|
||||
notifyLocalColorsChanged(regions, colors);
|
||||
} catch (RuntimeException e) {
|
||||
Log.e(TAG, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeLocalColorsAreas(@NonNull List<RectF> regions) {
|
||||
// No-OP
|
||||
}
|
||||
|
||||
private List<WallpaperColors> getLocalWallpaperColors(@NonNull List<RectF> areas,
|
||||
Bitmap b) {
|
||||
List<WallpaperColors> colors = new ArrayList<>(areas.size());
|
||||
for (int i = 0; i < areas.size(); i++) {
|
||||
RectF area = areas.get(i);
|
||||
if (area == null || !LOCAL_COLOR_BOUNDS.contains(area)) {
|
||||
colors.add(null);
|
||||
continue;
|
||||
}
|
||||
Rect subImage = new Rect(
|
||||
Math.round(area.left * b.getWidth()),
|
||||
Math.round(area.top * b.getHeight()),
|
||||
Math.round(area.right * b.getWidth()),
|
||||
Math.round(area.bottom * b.getHeight()));
|
||||
Bitmap colorImg = Bitmap.createBitmap(b,
|
||||
subImage.left, subImage.top, subImage.width(), subImage.height());
|
||||
WallpaperColors color = WallpaperColors.fromBitmap(colorImg);
|
||||
colors.add(color);
|
||||
}
|
||||
return colors;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceCreated(SurfaceHolder holder) {
|
||||
if (mWorker == null) return;
|
||||
|
||||
@@ -58,6 +58,14 @@ public class ImageWallpaperRenderer implements GLWallpaperRenderer {
|
||||
mWallpaper = new ImageGLWallpaper(mProgram);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
* @return
|
||||
*/
|
||||
public void useBitmap(Consumer<Bitmap> c) {
|
||||
mTexture.use(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWcgContent() {
|
||||
return mTexture.isWcgContent();
|
||||
|
||||
@@ -100,6 +100,7 @@ public class ImageWallpaperTest extends SysuiTestCase {
|
||||
return new ImageWallpaper() {
|
||||
@Override
|
||||
public Engine onCreateEngine() {
|
||||
onCreate();
|
||||
return new GLEngine(mHandler) {
|
||||
@Override
|
||||
public Context getDisplayContext() {
|
||||
|
||||
@@ -31,6 +31,7 @@ import android.annotation.NonNull;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.AppGlobals;
|
||||
import android.app.AppOpsManager;
|
||||
import android.app.ILocalWallpaperColorConsumer;
|
||||
import android.app.IWallpaperManager;
|
||||
import android.app.IWallpaperManagerCallback;
|
||||
import android.app.PendingIntent;
|
||||
@@ -59,6 +60,7 @@ import android.graphics.BitmapFactory;
|
||||
import android.graphics.BitmapRegionDecoder;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.hardware.display.DisplayManager;
|
||||
import android.os.Binder;
|
||||
import android.os.Bundle;
|
||||
@@ -85,7 +87,10 @@ import android.service.wallpaper.IWallpaperService;
|
||||
import android.service.wallpaper.WallpaperService;
|
||||
import android.system.ErrnoException;
|
||||
import android.system.Os;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
import android.util.EventLog;
|
||||
import android.util.Pair;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
import android.util.SparseBooleanArray;
|
||||
@@ -105,7 +110,6 @@ import com.android.server.EventLogTags;
|
||||
import com.android.server.FgThread;
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.SystemService;
|
||||
import com.android.server.SystemService.TargetUser;
|
||||
import com.android.server.pm.UserManagerInternal;
|
||||
import com.android.server.utils.TimingsTraceAndSlog;
|
||||
import com.android.server.wm.WindowManagerInternal;
|
||||
@@ -136,6 +140,8 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
|
||||
private static final String TAG = "WallpaperManagerService";
|
||||
private static final boolean DEBUG = false;
|
||||
private static final boolean DEBUG_LIVE = true;
|
||||
private static final @NonNull RectF LOCAL_COLOR_BOUNDS =
|
||||
new RectF(0, 0, 1, 1);
|
||||
|
||||
public static class Lifecycle extends SystemService {
|
||||
private IWallpaperManagerService mService;
|
||||
@@ -866,6 +872,12 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
|
||||
private final SparseBooleanArray mUserRestorecon = new SparseBooleanArray();
|
||||
private int mCurrentUserId = UserHandle.USER_NULL;
|
||||
private boolean mInAmbientMode;
|
||||
private ArrayMap<IBinder, ArraySet<RectF>> mLocalColorCallbackAreas =
|
||||
new ArrayMap<>();
|
||||
private ArrayMap<RectF, RemoteCallbackList<ILocalWallpaperColorConsumer>>
|
||||
mLocalColorAreaCallbacks = new ArrayMap<>();
|
||||
private ArrayMap<Integer, ArraySet<RectF>> mLocalColorDisplayIdAreas = new ArrayMap<>();
|
||||
private ArrayMap<IBinder, Integer> mLocalColorCallbackDisplayId = new ArrayMap<>();
|
||||
|
||||
static class WallpaperData {
|
||||
|
||||
@@ -1275,6 +1287,32 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLocalWallpaperColorsChanged(RectF area, WallpaperColors colors,
|
||||
int displayId) {
|
||||
forEachDisplayConnector(displayConnector -> {
|
||||
if (displayConnector.mDisplayId == displayId) {
|
||||
RemoteCallbackList<ILocalWallpaperColorConsumer> callbacks;
|
||||
ArrayMap<IBinder, Integer> callbackDisplayIds;
|
||||
synchronized (mLock) {
|
||||
callbacks = mLocalColorAreaCallbacks.get(area);
|
||||
callbackDisplayIds = new ArrayMap<>(mLocalColorCallbackDisplayId);
|
||||
}
|
||||
if (callbacks == null) return;
|
||||
callbacks.broadcast(c -> {
|
||||
try {
|
||||
int targetDisplayId =
|
||||
callbackDisplayIds.get(c.asBinder());
|
||||
if (targetDisplayId == displayId) c.onColorsChanged(area, colors);
|
||||
} catch (RemoteException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName name) {
|
||||
synchronized (mLock) {
|
||||
@@ -1437,6 +1475,15 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
|
||||
} catch (RemoteException e) {
|
||||
Slog.w(TAG, "Failed to request wallpaper colors", e);
|
||||
}
|
||||
|
||||
ArraySet<RectF> areas = mLocalColorDisplayIdAreas.get(displayId);
|
||||
if (areas != null && areas.size() != 0) {
|
||||
try {
|
||||
connector.mEngine.addLocalColorsAreas(new ArrayList<>(areas));
|
||||
} catch (RemoteException e) {
|
||||
Slog.w(TAG, "Failed to register local colors areas", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2340,6 +2387,115 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
|
||||
return true;
|
||||
}
|
||||
|
||||
private IWallpaperEngine getEngine(int which, int userId, int displayId) {
|
||||
WallpaperData wallpaperData = findWallpaperAtDisplay(userId, displayId);
|
||||
if (wallpaperData == null) return null;
|
||||
IWallpaperEngine engine = null;
|
||||
synchronized (mLock) {
|
||||
for (int i = 0; i < wallpaperData.connection.mDisplayConnector.size(); i++) {
|
||||
int id = wallpaperData.connection.mDisplayConnector.get(i).mDisplayId;
|
||||
int currentWhich = wallpaperData.connection.mDisplayConnector.get(i).mDisplayId;
|
||||
if (id != displayId && currentWhich != which) continue;
|
||||
engine = wallpaperData.connection.mDisplayConnector.get(i).mEngine;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return engine;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addOnLocalColorsChangedListener(@NonNull ILocalWallpaperColorConsumer callback,
|
||||
@NonNull List<RectF> regions, int which, int userId, int displayId)
|
||||
throws RemoteException {
|
||||
if (which != FLAG_LOCK && which != FLAG_SYSTEM) {
|
||||
throw new IllegalArgumentException("which should be either FLAG_LOCK or FLAG_SYSTEM");
|
||||
}
|
||||
IWallpaperEngine engine = getEngine(which, userId, displayId);
|
||||
if (engine == null) return;
|
||||
ArrayList<RectF> validAreas = new ArrayList<>(regions.size());
|
||||
synchronized (mLock) {
|
||||
ArraySet<RectF> areas = mLocalColorCallbackAreas.get(callback);
|
||||
if (areas == null) areas = new ArraySet<>(regions.size());
|
||||
areas.addAll(regions);
|
||||
mLocalColorCallbackAreas.put(callback.asBinder(), areas);
|
||||
}
|
||||
for (int i = 0; i < regions.size(); i++) {
|
||||
if (!LOCAL_COLOR_BOUNDS.contains(regions.get(i))) {
|
||||
continue;
|
||||
}
|
||||
RemoteCallbackList callbacks;
|
||||
synchronized (mLock) {
|
||||
callbacks = mLocalColorAreaCallbacks.get(
|
||||
regions.get(i));
|
||||
if (callbacks == null) {
|
||||
callbacks = new RemoteCallbackList();
|
||||
mLocalColorAreaCallbacks.put(regions.get(i), callbacks);
|
||||
}
|
||||
mLocalColorCallbackDisplayId.put(callback.asBinder(), displayId);
|
||||
ArraySet<RectF> displayAreas = mLocalColorDisplayIdAreas.get(displayId);
|
||||
if (displayAreas == null) {
|
||||
displayAreas = new ArraySet<>(1);
|
||||
mLocalColorDisplayIdAreas.put(displayId, displayAreas);
|
||||
}
|
||||
displayAreas.add(regions.get(i));
|
||||
}
|
||||
validAreas.add(regions.get(i));
|
||||
callbacks.register(callback);
|
||||
}
|
||||
engine.addLocalColorsAreas(validAreas);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeOnLocalColorsChangedListener(
|
||||
@NonNull ILocalWallpaperColorConsumer callback, int which, int userId,
|
||||
int displayId) throws RemoteException {
|
||||
if (which != FLAG_LOCK && which != FLAG_SYSTEM) {
|
||||
throw new IllegalArgumentException("which should be either FLAG_LOCK or FLAG_SYSTEM");
|
||||
}
|
||||
final UserHandle callingUser = Binder.getCallingUserHandle();
|
||||
if (callingUser.getIdentifier() != userId) {
|
||||
throw new SecurityException("calling user id does not match");
|
||||
}
|
||||
final long identity = Binder.clearCallingIdentity();
|
||||
ArrayList<RectF> removeAreas = new ArrayList<>();
|
||||
ArrayList<Pair<RemoteCallbackList, ILocalWallpaperColorConsumer>>
|
||||
callbacksToRemove = new ArrayList<>();
|
||||
try {
|
||||
synchronized (mLock) {
|
||||
ArraySet<RectF> areas = mLocalColorCallbackAreas.remove(callback.asBinder());
|
||||
mLocalColorCallbackDisplayId.remove(callback.asBinder());
|
||||
if (areas == null) areas = new ArraySet<>();
|
||||
for (RectF area : areas) {
|
||||
RemoteCallbackList callbacks = mLocalColorAreaCallbacks.get(area);
|
||||
if (callbacks == null) continue;
|
||||
callbacksToRemove.add(new Pair<>(callbacks, callback));
|
||||
if (callbacks.getRegisteredCallbackCount() == 0) {
|
||||
mLocalColorAreaCallbacks.remove(area);
|
||||
removeAreas.add(area);
|
||||
}
|
||||
ArraySet<RectF> displayAreas = mLocalColorDisplayIdAreas.get(displayId);
|
||||
if (displayAreas != null) {
|
||||
displayAreas.remove(area);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < callbacksToRemove.size(); i++) {
|
||||
Pair<RemoteCallbackList, ILocalWallpaperColorConsumer>
|
||||
pair = callbacksToRemove.get(i);
|
||||
pair.first.unregister(pair.second);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// ignore any exception
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
|
||||
if (removeAreas.size() == 0) return;
|
||||
IWallpaperEngine engine = getEngine(which, userId, displayId);
|
||||
if (engine == null) return;
|
||||
engine.removeLocalColorsAreas(removeAreas);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WallpaperColors getWallpaperColors(int which, int userId, int displayId)
|
||||
throws RemoteException {
|
||||
|
||||
Reference in New Issue
Block a user