blob: c78160ed0442c4ec4ba8dae34f0b0d156ec181fb [file] [log] [blame]
/*
* Copyright (C) 2022 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.clockwork.display.burninprotection;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.Shader;
import android.hardware.display.DisplayManager;
import android.util.Log;
import android.view.Display;
import android.view.Surface;
import android.view.SurfaceControl;
import android.view.WindowManager;
import android.view.WindowManagerPolicyConstants;
class ImageMaskView {
private static final String TAG = "BurnInProtector_IMV";
private static final int Z_ORDER = WindowManager.LayoutParams.TYPE_POINTER
* WindowManagerPolicyConstants.TYPE_LAYER_MULTIPLIER + 10;
private final SurfaceControl mSurfaceControl;
private final SurfaceControl.Transaction mSurfaceControlTransaction;
private final Surface mSurface;
private final Rect mDrawRect;
private final int mLayerStack;
private Bitmap mBitmapTile;
private int mMaskViewType;
private boolean mIsShowing;
ImageMaskView(Context context, Bitmap bitmapTile, int maskViewType) {
mBitmapTile = bitmapTile;
mDrawRect =
context.getSystemService(WindowManager.class).getCurrentWindowMetrics().getBounds();
mSurfaceControlTransaction = new SurfaceControl.Transaction();
mSurfaceControl =
new SurfaceControl.Builder()
.setName(ImageMaskView.class.getName())
.setBufferSize(mDrawRect.width(), mDrawRect.height())
.setFormat(PixelFormat.TRANSLUCENT)
.build();
mSurface = new Surface(mSurfaceControl);
Display display =
context.getSystemService(DisplayManager.class).getDisplay(Display.DEFAULT_DISPLAY);
if (display != null) {
mLayerStack = display.getLayerStack();
} else {
mLayerStack = 0;
}
mMaskViewType = maskViewType;
}
int getMaskViewType() {
return mMaskViewType;
}
private void visualizeBurnInForDebug(Canvas canvas) {
Paint p = new Paint();
p.setColor(Color.GREEN);
p.setTextAlign(Paint.Align.CENTER);
p.setTextSize(50);
canvas.drawText(
"BurnIn Mask: " + mMaskViewType, mDrawRect.centerX(), mDrawRect.centerY(), p);
}
private void redraw() {
if (!mSurface.isValid()) {
Log.w(TAG, "redraw: mSurface is not valid");
return;
}
try {
final Canvas canvas = mSurface.lockCanvas(mDrawRect);
if (canvas == null) {
return;
}
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
final Paint paint = new Paint();
final BitmapShader shader = new BitmapShader(mBitmapTile,
Shader.TileMode.REPEAT,
Shader.TileMode.REPEAT);
paint.setShader(shader);
canvas.drawRect(mDrawRect, paint);
if (BurnInProtector.DEBUG) {
visualizeBurnInForDebug(canvas);
}
mSurface.unlockCanvasAndPost(canvas);
} catch (IllegalArgumentException | Surface.OutOfResourcesException e) {
Log.e(TAG, "redraw: ", e);
}
}
void show() {
if (!mIsShowing) {
mIsShowing = true;
redraw();
mSurfaceControlTransaction
.setLayerStack(mSurfaceControl, mLayerStack)
.setLayer(mSurfaceControl, Z_ORDER)
.setPosition(mSurfaceControl, 0, 0)
.show(mSurfaceControl)
.apply();
}
}
void updateMaskType(int maskType, Bitmap bitmapTile) {
mBitmapTile = bitmapTile;
mMaskViewType = maskType;
if (mIsShowing) {
redraw();
}
}
void hide() {
if (mIsShowing) {
mIsShowing = false;
mSurfaceControlTransaction.hide(mSurfaceControl)
.apply();
if (mSurface.isValid()) {
mSurface.release();
}
}
}
}