CircularDisplayMask.java revision ca5b9cfc07b345b373da1ced5384975e269dd7ac
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 17package com.android.server.wm; 18 19 20import android.graphics.Canvas; 21import android.graphics.Color; 22import android.graphics.Paint; 23import android.graphics.PixelFormat; 24import android.graphics.PorterDuff; 25import android.graphics.Rect; 26import android.view.Display; 27import android.view.Surface; 28import android.view.Surface.OutOfResourcesException; 29import android.view.SurfaceControl; 30import android.view.SurfaceSession; 31 32class CircularDisplayMask { 33 private static final String TAG = "CircularDisplayMask"; 34 35 private static final int STROKE_WIDTH = 2; 36 // half the screen size 37 private static final int CIRCLE_RADIUS = 160; 38 // size of the chin 39 private static final int SCREEN_OFFSET = 30; 40 41 private final SurfaceControl mSurfaceControl; 42 private final Surface mSurface = new Surface(); 43 private int mLastDW; 44 private int mLastDH; 45 private boolean mDrawNeeded; 46 private Paint mPaint; 47 private int mRotation; 48 private boolean mVisible; 49 50 public CircularDisplayMask(Display display, SurfaceSession session, int zOrder) { 51 SurfaceControl ctrl = null; 52 try { 53 ctrl = new SurfaceControl(session, "CircularDisplayMask", 54 320, 320, PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN); 55 ctrl.setLayerStack(display.getLayerStack()); 56 ctrl.setLayer(zOrder); 57 ctrl.setPosition(0, 0); 58 ctrl.show(); 59 mSurface.copyFrom(ctrl); 60 } catch (OutOfResourcesException e) { 61 } 62 mSurfaceControl = ctrl; 63 mDrawNeeded = true; 64 mPaint = new Paint(); 65 mPaint.setAntiAlias(true); 66 mPaint.setStyle(Paint.Style.STROKE); 67 mPaint.setColor(Color.BLACK); 68 mPaint.setStrokeWidth(STROKE_WIDTH); 69 } 70 71 private void drawIfNeeded() { 72 if (!mDrawNeeded || !mVisible) { 73 return; 74 } 75 mDrawNeeded = false; 76 77 Rect dirty = new Rect(0, 0, 320, 320); 78 Canvas c = null; 79 try { 80 c = mSurface.lockCanvas(dirty); 81 } catch (IllegalArgumentException e) { 82 } catch (Surface.OutOfResourcesException e) { 83 } 84 if (c == null) { 85 return; 86 } 87 c.drawColor(Color.TRANSPARENT, PorterDuff.Mode.SRC); 88 switch (mRotation) { 89 case Surface.ROTATION_0: 90 case Surface.ROTATION_90: 91 // chin bottom or right 92 mSurfaceControl.setPosition(0, 0); 93 break; 94 case Surface.ROTATION_180: 95 // chin top 96 mSurfaceControl.setPosition(0, -SCREEN_OFFSET); 97 break; 98 case Surface.ROTATION_270: 99 // chin left 100 mSurfaceControl.setPosition(-SCREEN_OFFSET, 0); 101 break; 102 } 103 c.drawCircle(CIRCLE_RADIUS, CIRCLE_RADIUS, CIRCLE_RADIUS, mPaint); 104 mSurface.unlockCanvasAndPost(c); 105 } 106 107 // Note: caller responsible for being inside 108 // Surface.openTransaction() / closeTransaction() 109 public void setVisibility(boolean on) { 110 if (mSurfaceControl == null) { 111 return; 112 } 113 mVisible = on; 114 drawIfNeeded(); 115 if (on) { 116 mSurfaceControl.show(); 117 } else { 118 mSurfaceControl.hide(); 119 } 120 } 121 122 void positionSurface(int dw, int dh, int rotation) { 123 if (mLastDW == dw && mLastDH == dh && mRotation == rotation) { 124 return; 125 } 126 mLastDW = dw; 127 mLastDH = dh; 128 mDrawNeeded = true; 129 mRotation = rotation; 130 drawIfNeeded(); 131 } 132 133} 134