blob: 26619235a826e1c18be1c8c9a3f6e1e872292361 [file] [log] [blame]
/*
* 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 com.android.wallpaper.picker;
import android.app.WallpaperColors;
import android.content.Context;
import android.os.Bundle;
import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import androidx.annotation.Nullable;
import com.android.wallpaper.R;
import com.android.wallpaper.util.PreviewUtils;
import com.android.wallpaper.util.SurfaceViewUtils;
import java.util.concurrent.atomic.AtomicBoolean;
/** A surface holder callback that renders user's workspace on the passed in surface view. */
public class WorkspaceSurfaceHolderCallback implements SurfaceHolder.Callback {
/**
* Listener to be called when workspace surface is updated with a new Surface Package.
*/
public interface WorkspaceRenderListener {
/**
* Called on the main thread after the workspace surface is updated from the provider
*/
void onWorkspaceRendered();
}
private static final String TAG = "WsSurfaceHolderCallback";
private static final String KEY_WALLPAPER_COLORS = "wallpaper_colors";
private final SurfaceView mWorkspaceSurface;
private final PreviewUtils mPreviewUtils;
private final boolean mShouldUseWallpaperColors;
private final AtomicBoolean mRequestPending = new AtomicBoolean(false);
private WallpaperColors mWallpaperColors;
private boolean mIsWallpaperColorsReady;
private Surface mLastSurface;
private Message mCallback;
private WorkspaceRenderListener mListener;
private boolean mNeedsToCleanUp;
public WorkspaceSurfaceHolderCallback(SurfaceView workspaceSurface, Context context) {
this(workspaceSurface, context, false);
}
/**
* Creates a new instance of {@link WorkspaceSurfaceHolderCallback} specifying if wallpaper
* colors should be used to preview the workspace.
*
* @param shouldUseWallpaperColors if true, the workspace preview won't be requested until both
* the surface is created and wallpaper colors are set via
* {@link #setWallpaperColors(WallpaperColors)}
*/
public WorkspaceSurfaceHolderCallback(SurfaceView workspaceSurface, Context context,
boolean shouldUseWallpaperColors) {
mWorkspaceSurface = workspaceSurface;
mPreviewUtils = new PreviewUtils(context,
context.getString(R.string.grid_control_metadata_name));
mShouldUseWallpaperColors = shouldUseWallpaperColors;
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
if (mPreviewUtils.supportsPreview() && mLastSurface != holder.getSurface()) {
mLastSurface = holder.getSurface();
maybeRenderPreview();
}
}
/**
* Set the current wallpaper's colors. This method must be called if this instance was created
* with shouldUseWallpaperColors = true (even with {@code null} colors), and conversely, calling
* this method when {@code shouldUseWallpaperColors = false} will be a no-op.
*
* @param colors WallpaperColors extracted from the current wallpaper preview, or {@code null}
* if none are available.
* @see #WorkspaceSurfaceHolderCallback(SurfaceView, Context, boolean)
*/
public void setWallpaperColors(@Nullable WallpaperColors colors) {
if (!mShouldUseWallpaperColors) {
return;
}
mWallpaperColors = colors;
mIsWallpaperColorsReady = true;
maybeRenderPreview();
}
public void setListener(WorkspaceRenderListener listener) {
mListener = listener;
}
private void maybeRenderPreview() {
if ((mShouldUseWallpaperColors && !mIsWallpaperColorsReady) || mLastSurface == null) {
return;
}
mRequestPending.set(true);
requestPreview(mWorkspaceSurface, (result) -> {
mRequestPending.set(false);
if (result != null && mLastSurface != null) {
mWorkspaceSurface.setChildSurfacePackage(
SurfaceViewUtils.getSurfacePackage(result));
mCallback = SurfaceViewUtils.getCallback(result);
if (mNeedsToCleanUp) {
cleanUp();
} else if (mListener != null) {
mListener.onWorkspaceRendered();
}
}
});
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { }
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
public void cleanUp() {
if (mCallback != null) {
try {
mCallback.replyTo.send(mCallback);
mNeedsToCleanUp = false;
} catch (RemoteException e) {
Log.w(TAG, "Couldn't call cleanup on workspace preview", e);
} finally {
mCallback = null;
}
} else {
if (mRequestPending.get()) {
mNeedsToCleanUp = true;
}
}
}
public void resetLastSurface() {
mLastSurface = null;
}
protected void requestPreview(SurfaceView workspaceSurface,
PreviewUtils.WorkspacePreviewCallback callback) {
if (workspaceSurface.getDisplay() == null) {
Log.w(TAG,
"No display ID, avoiding asking for workspace preview, lest WallpaperPicker "
+ "crash");
return;
}
Bundle request = SurfaceViewUtils.createSurfaceViewRequest(workspaceSurface);
if (mWallpaperColors != null) {
request.putParcelable(KEY_WALLPAPER_COLORS, mWallpaperColors);
}
mPreviewUtils.renderPreview(request, callback);
}
}