/* * Copyright (C) 2011 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.server.wm; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.PorterDuff; import android.graphics.Rect; import android.graphics.Typeface; import android.graphics.Paint.FontMetricsInt; import android.util.DisplayMetrics; import android.util.Log; import android.util.TypedValue; import android.view.Display; import android.view.Surface.OutOfResourcesException; import android.view.Surface; import android.view.SurfaceControl; import android.view.SurfaceSession; /** * Displays a watermark on top of the window manager's windows. */ class Watermark { private final Display mDisplay; private final String[] mTokens; private final String mText; private final Paint mTextPaint; private final int mTextWidth; private final int mTextHeight; private final int mDeltaX; private final int mDeltaY; private final SurfaceControl mSurfaceControl; private final Surface mSurface = new Surface(); private int mLastDW; private int mLastDH; private boolean mDrawNeeded; Watermark(Display display, DisplayMetrics dm, SurfaceSession session, String[] tokens) { if (false) { Log.i(WindowManagerService.TAG, "*********************** WATERMARK"); for (int i=0; i<tokens.length; i++) { Log.i(WindowManagerService.TAG, " TOKEN #" + i + ": " + tokens[i]); } } mDisplay = display; mTokens = tokens; StringBuilder builder = new StringBuilder(32); int len = mTokens[0].length(); len = len & ~1; for (int i=0; i<len; i+=2) { int c1 = mTokens[0].charAt(i); int c2 = mTokens[0].charAt(i+1); if (c1 >= 'a' && c1 <= 'f') c1 = c1 - 'a' + 10; else if (c1 >= 'A' && c1 <= 'F') c1 = c1 - 'A' + 10; else c1 -= '0'; if (c2 >= 'a' && c2 <= 'f') c2 = c2 - 'a' + 10; else if (c2 >= 'A' && c2 <= 'F') c2 = c2 - 'A' + 10; else c2 -= '0'; builder.append((char)(255-((c1*16)+c2))); } mText = builder.toString(); if (false) { Log.i(WindowManagerService.TAG, "Final text: " + mText); } int fontSize = WindowManagerService.getPropertyInt(tokens, 1, TypedValue.COMPLEX_UNIT_DIP, 20, dm); mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mTextPaint.setTextSize(fontSize); mTextPaint.setTypeface(Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD)); FontMetricsInt fm = mTextPaint.getFontMetricsInt(); mTextWidth = (int)mTextPaint.measureText(mText); mTextHeight = fm.descent - fm.ascent; mDeltaX = WindowManagerService.getPropertyInt(tokens, 2, TypedValue.COMPLEX_UNIT_PX, mTextWidth*2, dm); mDeltaY = WindowManagerService.getPropertyInt(tokens, 3, TypedValue.COMPLEX_UNIT_PX, mTextHeight*3, dm); int shadowColor = WindowManagerService.getPropertyInt(tokens, 4, TypedValue.COMPLEX_UNIT_PX, 0xb0000000, dm); int color = WindowManagerService.getPropertyInt(tokens, 5, TypedValue.COMPLEX_UNIT_PX, 0x60ffffff, dm); int shadowRadius = WindowManagerService.getPropertyInt(tokens, 6, TypedValue.COMPLEX_UNIT_PX, 7, dm); int shadowDx = WindowManagerService.getPropertyInt(tokens, 8, TypedValue.COMPLEX_UNIT_PX, 0, dm); int shadowDy = WindowManagerService.getPropertyInt(tokens, 9, TypedValue.COMPLEX_UNIT_PX, 0, dm); mTextPaint.setColor(color); mTextPaint.setShadowLayer(shadowRadius, shadowDx, shadowDy, shadowColor); SurfaceControl ctrl = null; try { ctrl = new SurfaceControl(session, "WatermarkSurface", 1, 1, PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN); ctrl.setLayerStack(mDisplay.getLayerStack()); ctrl.setLayer(WindowManagerService.TYPE_LAYER_MULTIPLIER*100); ctrl.setPosition(0, 0); ctrl.show(); mSurface.copyFrom(ctrl); } catch (OutOfResourcesException e) { } mSurfaceControl = ctrl; } void positionSurface(int dw, int dh) { if (mLastDW != dw || mLastDH != dh) { mLastDW = dw; mLastDH = dh; mSurfaceControl.setSize(dw, dh); mDrawNeeded = true; } } void drawIfNeeded() { if (mDrawNeeded) { final int dw = mLastDW; final int dh = mLastDH; mDrawNeeded = false; Rect dirty = new Rect(0, 0, dw, dh); Canvas c = null; try { c = mSurface.lockCanvas(dirty); } catch (IllegalArgumentException e) { } catch (Surface.OutOfResourcesException e) { } if (c != null) { c.drawColor(0, PorterDuff.Mode.CLEAR); int deltaX = mDeltaX; int deltaY = mDeltaY; // deltaX shouldn't be close to a round fraction of our // x step, or else things will line up too much. int div = (dw+mTextWidth)/deltaX; int rem = (dw+mTextWidth) - (div*deltaX); int qdelta = deltaX/4; if (rem < qdelta || rem > (deltaX-qdelta)) { deltaX += deltaX/3; } int y = -mTextHeight; int x = -mTextWidth; while (y < (dh+mTextHeight)) { c.drawText(mText, x, y, mTextPaint); x += deltaX; if (x >= dw) { x -= (dw+mTextWidth); y += deltaY; } } mSurface.unlockCanvasAndPost(c); } } } }