1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.wm; 18 19 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 20 21 import android.graphics.BLASTBufferQueue; 22 import android.graphics.Canvas; 23 import android.graphics.Paint; 24 import android.graphics.Paint.FontMetricsInt; 25 import android.graphics.PixelFormat; 26 import android.graphics.PorterDuff; 27 import android.graphics.Typeface; 28 import android.util.DisplayMetrics; 29 import android.util.Log; 30 import android.util.TypedValue; 31 import android.view.Surface; 32 import android.view.Surface.OutOfResourcesException; 33 import android.view.SurfaceControl; 34 35 /** 36 * Displays a watermark on top of the window manager's windows. 37 */ 38 class Watermark { 39 private static final String TITLE = "WatermarkSurface"; 40 41 private final String mText; 42 private final Paint mTextPaint; 43 private final int mTextWidth; 44 private final int mTextHeight; 45 private final int mDeltaX; 46 private final int mDeltaY; 47 48 private final SurfaceControl mSurfaceControl; 49 private final Surface mSurface; 50 private final BLASTBufferQueue mBlastBufferQueue; 51 52 private int mLastDW; 53 private int mLastDH; 54 private boolean mDrawNeeded; 55 Watermark(DisplayContent dc, DisplayMetrics dm, String[] tokens, SurfaceControl.Transaction t)56 Watermark(DisplayContent dc, DisplayMetrics dm, String[] tokens, SurfaceControl.Transaction t) { 57 if (false) { 58 Log.i(TAG_WM, "*********************** WATERMARK"); 59 for (int i=0; i<tokens.length; i++) { 60 Log.i(TAG_WM, " TOKEN #" + i + ": " + tokens[i]); 61 } 62 } 63 64 StringBuilder builder = new StringBuilder(32); 65 int len = tokens[0].length(); 66 len = len & ~1; 67 for (int i=0; i<len; i+=2) { 68 int c1 = tokens[0].charAt(i); 69 int c2 = tokens[0].charAt(i + 1); 70 if (c1 >= 'a' && c1 <= 'f') c1 = c1 - 'a' + 10; 71 else if (c1 >= 'A' && c1 <= 'F') c1 = c1 - 'A' + 10; 72 else c1 -= '0'; 73 if (c2 >= 'a' && c2 <= 'f') c2 = c2 - 'a' + 10; 74 else if (c2 >= 'A' && c2 <= 'F') c2 = c2 - 'A' + 10; 75 else c2 -= '0'; 76 builder.append((char)(255-((c1*16)+c2))); 77 } 78 mText = builder.toString(); 79 if (false) { 80 Log.i(TAG_WM, "Final text: " + mText); 81 } 82 83 int fontSize = WindowManagerService.getPropertyInt(tokens, 1, 84 TypedValue.COMPLEX_UNIT_DIP, 20, dm); 85 86 mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 87 mTextPaint.setTextSize(fontSize); 88 mTextPaint.setTypeface(Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD)); 89 90 FontMetricsInt fm = mTextPaint.getFontMetricsInt(); 91 mTextWidth = (int)mTextPaint.measureText(mText); 92 mTextHeight = fm.descent - fm.ascent; 93 94 mDeltaX = WindowManagerService.getPropertyInt(tokens, 2, 95 TypedValue.COMPLEX_UNIT_PX, mTextWidth*2, dm); 96 mDeltaY = WindowManagerService.getPropertyInt(tokens, 3, 97 TypedValue.COMPLEX_UNIT_PX, mTextHeight*3, dm); 98 int shadowColor = WindowManagerService.getPropertyInt(tokens, 4, 99 TypedValue.COMPLEX_UNIT_PX, 0xb0000000, dm); 100 int color = WindowManagerService.getPropertyInt(tokens, 5, 101 TypedValue.COMPLEX_UNIT_PX, 0x60ffffff, dm); 102 int shadowRadius = WindowManagerService.getPropertyInt(tokens, 6, 103 TypedValue.COMPLEX_UNIT_PX, 7, dm); 104 int shadowDx = WindowManagerService.getPropertyInt(tokens, 8, 105 TypedValue.COMPLEX_UNIT_PX, 0, dm); 106 int shadowDy = WindowManagerService.getPropertyInt(tokens, 9, 107 TypedValue.COMPLEX_UNIT_PX, 0, dm); 108 109 mTextPaint.setColor(color); 110 mTextPaint.setShadowLayer(shadowRadius, shadowDx, shadowDy, shadowColor); 111 112 SurfaceControl ctrl = null; 113 try { 114 ctrl = dc.makeOverlay() 115 .setName(TITLE) 116 .setBLASTLayer() 117 .setFormat(PixelFormat.TRANSLUCENT) 118 .setCallsite(TITLE) 119 .build(); 120 t.setLayer(ctrl, WindowManagerService.TYPE_LAYER_MULTIPLIER * 100) 121 .setPosition(ctrl, 0, 0) 122 .show(ctrl); 123 // Ensure we aren't considered as obscuring for Input purposes. 124 InputMonitor.setTrustedOverlayInputInfo(ctrl, t, dc.getDisplayId(), TITLE); 125 } catch (OutOfResourcesException e) { 126 } 127 mSurfaceControl = ctrl; 128 mBlastBufferQueue = new BLASTBufferQueue(TITLE, mSurfaceControl, 1 /* width */, 129 1 /* height */, PixelFormat.RGBA_8888); 130 mSurface = mBlastBufferQueue.createSurface(); 131 } 132 positionSurface(int dw, int dh, SurfaceControl.Transaction t)133 void positionSurface(int dw, int dh, SurfaceControl.Transaction t) { 134 if (mLastDW != dw || mLastDH != dh) { 135 mLastDW = dw; 136 mLastDH = dh; 137 t.setBufferSize(mSurfaceControl, dw, dh); 138 mDrawNeeded = true; 139 } 140 } 141 drawIfNeeded()142 void drawIfNeeded() { 143 if (!mDrawNeeded) { 144 return; 145 } 146 147 final int dw = mLastDW; 148 final int dh = mLastDH; 149 150 mDrawNeeded = false; 151 mBlastBufferQueue.update(mSurfaceControl, dw, dh, PixelFormat.RGBA_8888); 152 Canvas c = null; 153 try { 154 c = mSurface.lockCanvas(null); 155 } catch (IllegalArgumentException | OutOfResourcesException e) { 156 } 157 if (c != null) { 158 c.drawColor(0, PorterDuff.Mode.CLEAR); 159 160 int deltaX = mDeltaX; 161 int deltaY = mDeltaY; 162 163 // deltaX shouldn't be close to a round fraction of our 164 // x step, or else things will line up too much. 165 int div = (dw + mTextWidth) / deltaX; 166 int rem = (dw + mTextWidth) - (div * deltaX); 167 int qdelta = deltaX / 4; 168 if (rem < qdelta || rem > (deltaX - qdelta)) { 169 deltaX += deltaX / 3; 170 } 171 172 int y = -mTextHeight; 173 int x = -mTextWidth; 174 while (y < (dh + mTextHeight)) { 175 c.drawText(mText, x, y, mTextPaint); 176 x += deltaX; 177 if (x >= dw) { 178 x -= (dw + mTextWidth); 179 y += deltaY; 180 } 181 } 182 mSurface.unlockCanvasAndPost(c); 183 } 184 } 185 } 186