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.Canvas;
22 import android.graphics.Paint;
23 import android.graphics.Paint.FontMetricsInt;
24 import android.graphics.PixelFormat;
25 import android.graphics.PorterDuff;
26 import android.graphics.Rect;
27 import android.graphics.Typeface;
28 import android.util.DisplayMetrics;
29 import android.util.Log;
30 import android.util.TypedValue;
31 import android.view.Display;
32 import android.view.Surface;
33 import android.view.Surface.OutOfResourcesException;
34 import android.view.SurfaceControl;
35 
36 /**
37  * Displays a watermark on top of the window manager's windows.
38  */
39 class Watermark {
40     private final Display mDisplay;
41     private final String[] mTokens;
42     private final String mText;
43     private final Paint mTextPaint;
44     private final int mTextWidth;
45     private final int mTextHeight;
46     private final int mDeltaX;
47     private final int mDeltaY;
48 
49     private final SurfaceControl mSurfaceControl;
50     private final Surface mSurface = new Surface();
51     private int mLastDW;
52     private int mLastDH;
53     private boolean mDrawNeeded;
54 
Watermark(DisplayContent dc, DisplayMetrics dm, String[] tokens)55     Watermark(DisplayContent dc, DisplayMetrics dm, String[] tokens) {
56         if (false) {
57             Log.i(TAG_WM, "*********************** WATERMARK");
58             for (int i=0; i<tokens.length; i++) {
59                 Log.i(TAG_WM, "  TOKEN #" + i + ": " + tokens[i]);
60             }
61         }
62 
63         mDisplay = dc.getDisplay();
64         mTokens = tokens;
65 
66         StringBuilder builder = new StringBuilder(32);
67         int len = mTokens[0].length();
68         len = len & ~1;
69         for (int i=0; i<len; i+=2) {
70             int c1 = mTokens[0].charAt(i);
71             int c2 = mTokens[0].charAt(i+1);
72             if (c1 >= 'a' && c1 <= 'f') c1 = c1 - 'a' + 10;
73             else if (c1 >= 'A' && c1 <= 'F') c1 = c1 - 'A' + 10;
74             else c1 -= '0';
75             if (c2 >= 'a' && c2 <= 'f') c2 = c2 - 'a' + 10;
76             else if (c2 >= 'A' && c2 <= 'F') c2 = c2 - 'A' + 10;
77             else c2 -= '0';
78             builder.append((char)(255-((c1*16)+c2)));
79         }
80         mText = builder.toString();
81         if (false) {
82             Log.i(TAG_WM, "Final text: " + mText);
83         }
84 
85         int fontSize = WindowManagerService.getPropertyInt(tokens, 1,
86                 TypedValue.COMPLEX_UNIT_DIP, 20, dm);
87 
88         mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
89         mTextPaint.setTextSize(fontSize);
90         mTextPaint.setTypeface(Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD));
91 
92         FontMetricsInt fm = mTextPaint.getFontMetricsInt();
93         mTextWidth = (int)mTextPaint.measureText(mText);
94         mTextHeight = fm.descent - fm.ascent;
95 
96         mDeltaX = WindowManagerService.getPropertyInt(tokens, 2,
97                 TypedValue.COMPLEX_UNIT_PX, mTextWidth*2, dm);
98         mDeltaY = WindowManagerService.getPropertyInt(tokens, 3,
99                 TypedValue.COMPLEX_UNIT_PX, mTextHeight*3, dm);
100         int shadowColor = WindowManagerService.getPropertyInt(tokens, 4,
101                 TypedValue.COMPLEX_UNIT_PX, 0xb0000000, dm);
102         int color = WindowManagerService.getPropertyInt(tokens, 5,
103                 TypedValue.COMPLEX_UNIT_PX, 0x60ffffff, dm);
104         int shadowRadius = WindowManagerService.getPropertyInt(tokens, 6,
105                 TypedValue.COMPLEX_UNIT_PX, 7, dm);
106         int shadowDx = WindowManagerService.getPropertyInt(tokens, 8,
107                 TypedValue.COMPLEX_UNIT_PX, 0, dm);
108         int shadowDy = WindowManagerService.getPropertyInt(tokens, 9,
109                 TypedValue.COMPLEX_UNIT_PX, 0, dm);
110 
111         mTextPaint.setColor(color);
112         mTextPaint.setShadowLayer(shadowRadius, shadowDx, shadowDy, shadowColor);
113 
114         SurfaceControl ctrl = null;
115         try {
116             ctrl = dc.makeOverlay()
117                     .setName("WatermarkSurface")
118                     .setBufferSize(1, 1)
119                     .setFormat(PixelFormat.TRANSLUCENT)
120                     .build();
121             ctrl.setLayerStack(mDisplay.getLayerStack());
122             ctrl.setLayer(WindowManagerService.TYPE_LAYER_MULTIPLIER*100);
123             ctrl.setPosition(0, 0);
124             ctrl.show();
125             mSurface.copyFrom(ctrl);
126         } catch (OutOfResourcesException e) {
127         }
128         mSurfaceControl = ctrl;
129     }
130 
positionSurface(int dw, int dh)131     void positionSurface(int dw, int dh) {
132         if (mLastDW != dw || mLastDH != dh) {
133             mLastDW = dw;
134             mLastDH = dh;
135             mSurfaceControl.setBufferSize(dw, dh);
136             mDrawNeeded = true;
137         }
138     }
139 
drawIfNeeded()140     void drawIfNeeded() {
141         if (mDrawNeeded) {
142             final int dw = mLastDW;
143             final int dh = mLastDH;
144 
145             mDrawNeeded = false;
146             Rect dirty = new Rect(0, 0, dw, dh);
147             Canvas c = null;
148             try {
149                 c = mSurface.lockCanvas(dirty);
150             } catch (IllegalArgumentException e) {
151             } catch (Surface.OutOfResourcesException e) {
152             }
153             if (c != null) {
154                 c.drawColor(0, PorterDuff.Mode.CLEAR);
155 
156                 int deltaX = mDeltaX;
157                 int deltaY = mDeltaY;
158 
159                 // deltaX shouldn't be close to a round fraction of our
160                 // x step, or else things will line up too much.
161                 int div = (dw+mTextWidth)/deltaX;
162                 int rem = (dw+mTextWidth) - (div*deltaX);
163                 int qdelta = deltaX/4;
164                 if (rem < qdelta || rem > (deltaX-qdelta)) {
165                     deltaX += deltaX/3;
166                 }
167 
168                 int y = -mTextHeight;
169                 int x = -mTextWidth;
170                 while (y < (dh+mTextHeight)) {
171                     c.drawText(mText, x, y, mTextPaint);
172                     x += deltaX;
173                     if (x >= dw) {
174                         x -= (dw+mTextWidth);
175                         y += deltaY;
176                     }
177                 }
178                 mSurface.unlockCanvasAndPost(c);
179             }
180         }
181     }
182 }
183