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