1 /* 2 * Copyright (C) 2014 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 20 21 import android.graphics.Canvas; 22 import android.graphics.Color; 23 import android.graphics.Paint; 24 import android.graphics.PixelFormat; 25 import android.graphics.Point; 26 import android.graphics.PorterDuff; 27 import android.graphics.PorterDuffXfermode; 28 import android.graphics.Rect; 29 import android.view.Display; 30 import android.view.Surface; 31 import android.view.Surface.OutOfResourcesException; 32 import android.view.SurfaceControl; 33 import android.view.SurfaceSession; 34 import android.util.Slog; 35 36 class CircularDisplayMask { 37 private static final String TAG = "CircularDisplayMask"; 38 39 // size of the chin 40 private int mScreenOffset = 0; 41 // Display dimensions 42 private Point mScreenSize; 43 44 private final SurfaceControl mSurfaceControl; 45 private final Surface mSurface = new Surface(); 46 private int mLastDW; 47 private int mLastDH; 48 private boolean mDrawNeeded; 49 private Paint mPaint; 50 private int mRotation; 51 private boolean mVisible; 52 private boolean mDimensionsUnequal = false; 53 54 public CircularDisplayMask(Display display, SurfaceSession session, int zOrder, 55 int screenOffset) { 56 mScreenSize = new Point(); 57 display.getSize(mScreenSize); 58 if (mScreenSize.x != mScreenSize.y) { 59 Slog.w(TAG, "Screen dimensions of displayId = " + display.getDisplayId() + 60 "are not equal, circularMask will not be drawn."); 61 mDimensionsUnequal = true; 62 } 63 64 SurfaceControl ctrl = null; 65 try { 66 if (WindowManagerService.DEBUG_SURFACE_TRACE) { 67 ctrl = new WindowStateAnimator.SurfaceTrace(session, "CircularDisplayMask", 68 mScreenSize.x, mScreenSize.y, PixelFormat.TRANSLUCENT, 69 SurfaceControl.HIDDEN); 70 } else { 71 ctrl = new SurfaceControl(session, "CircularDisplayMask", mScreenSize.x, 72 mScreenSize.y, PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN); 73 } 74 ctrl.setLayerStack(display.getLayerStack()); 75 ctrl.setLayer(zOrder); 76 ctrl.setPosition(0, 0); 77 ctrl.show(); 78 mSurface.copyFrom(ctrl); 79 } catch (OutOfResourcesException e) { 80 } 81 mSurfaceControl = ctrl; 82 mDrawNeeded = true; 83 mPaint = new Paint(); 84 mPaint.setAntiAlias(true); 85 mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); 86 mScreenOffset = screenOffset; 87 } 88 89 private void drawIfNeeded() { 90 if (!mDrawNeeded || !mVisible || mDimensionsUnequal) { 91 return; 92 } 93 mDrawNeeded = false; 94 95 Rect dirty = new Rect(0, 0, mScreenSize.x, mScreenSize.y); 96 Canvas c = null; 97 try { 98 c = mSurface.lockCanvas(dirty); 99 } catch (IllegalArgumentException e) { 100 } catch (Surface.OutOfResourcesException e) { 101 } 102 if (c == null) { 103 return; 104 } 105 switch (mRotation) { 106 case Surface.ROTATION_0: 107 case Surface.ROTATION_90: 108 // chin bottom or right 109 mSurfaceControl.setPosition(0, 0); 110 break; 111 case Surface.ROTATION_180: 112 // chin top 113 mSurfaceControl.setPosition(0, -mScreenOffset); 114 break; 115 case Surface.ROTATION_270: 116 // chin left 117 mSurfaceControl.setPosition(-mScreenOffset, 0); 118 break; 119 } 120 121 int circleRadius = mScreenSize.x / 2; 122 c.drawColor(Color.BLACK); 123 124 // The radius is reduced by 1 to provide an anti aliasing effect on the display edges. 125 c.drawCircle(circleRadius, circleRadius, circleRadius - 1, mPaint); 126 mSurface.unlockCanvasAndPost(c); 127 } 128 129 // Note: caller responsible for being inside 130 // Surface.openTransaction() / closeTransaction() 131 public void setVisibility(boolean on) { 132 if (mSurfaceControl == null) { 133 return; 134 } 135 mVisible = on; 136 drawIfNeeded(); 137 if (on) { 138 mSurfaceControl.show(); 139 } else { 140 mSurfaceControl.hide(); 141 } 142 } 143 144 void positionSurface(int dw, int dh, int rotation) { 145 if (mLastDW == dw && mLastDH == dh && mRotation == rotation) { 146 return; 147 } 148 mLastDW = dw; 149 mLastDH = dh; 150 mDrawNeeded = true; 151 mRotation = rotation; 152 drawIfNeeded(); 153 } 154 155 } 156