• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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