1 /* 2 * Copyright (C) 2020 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 android.server.wm.overlay; 18 19 import static android.view.Display.DEFAULT_DISPLAY; 20 21 import android.app.Service; 22 import android.content.Context; 23 import android.content.Intent; 24 import android.graphics.PixelFormat; 25 import android.hardware.display.DisplayManager; 26 import android.os.Handler; 27 import android.os.IBinder; 28 import android.os.Looper; 29 import android.os.RemoteException; 30 import android.server.wm.shared.IUntrustedTouchTestService; 31 import android.util.ArrayMap; 32 import android.view.Display; 33 import android.view.View; 34 import android.view.WindowManager; 35 import android.view.WindowManager.LayoutParams; 36 import android.widget.Toast; 37 38 import androidx.annotation.Nullable; 39 40 import java.util.Collections; 41 import java.util.Map; 42 43 44 public class UntrustedTouchTestService extends Service { 45 public static final int BACKGROUND_COLOR = 0xFF00FF00; 46 47 /** Map from view to the service manager that manages it. */ 48 private final Map<View, WindowManager> mViewManagers = Collections.synchronizedMap( 49 new ArrayMap<>()); 50 51 /** Can only be accessed from the main thread. */ 52 private Toast mToast; 53 54 private final IUntrustedTouchTestService mBinder = new Binder(); 55 private volatile Handler mMainHandler; 56 private volatile Context mSawContext; 57 private volatile WindowManager mWindowManager; 58 private volatile WindowManager mSawWindowManager; 59 60 @Override onCreate()61 public void onCreate() { 62 mMainHandler = new Handler(Looper.getMainLooper()); 63 mWindowManager = getSystemService(WindowManager.class); 64 mSawContext = getContextForSaw(this); 65 mSawWindowManager = mSawContext.getSystemService(WindowManager.class); 66 } 67 68 @Nullable 69 @Override onBind(Intent intent)70 public IBinder onBind(Intent intent) { 71 return mBinder.asBinder(); 72 } 73 74 @Override onDestroy()75 public void onDestroy() { 76 removeOverlays(); 77 } 78 79 private class Binder extends IUntrustedTouchTestService.Stub { 80 private final UntrustedTouchTestService mService = UntrustedTouchTestService.this; 81 82 @Override showToast()83 public void showToast() { 84 mMainHandler.post(() -> { 85 mToast = Toast.makeText(mService, "Toast " + getPackageName(), Toast.LENGTH_LONG); 86 mToast.show(); 87 }); 88 } 89 90 @Override showSystemAlertWindow(String name, float opacity, int viewX, int viewY)91 public void showSystemAlertWindow(String name, float opacity, int viewX, int viewY) { 92 View view = getView(mSawContext); 93 LayoutParams params = newOverlayLayoutParams(name, 94 LayoutParams.TYPE_APPLICATION_OVERLAY); 95 params.setTitle(name); 96 params.alpha = opacity; 97 params.x = viewX; 98 params.y = viewY; 99 mMainHandler.post(() -> mSawWindowManager.addView(view, params)); 100 mViewManagers.put(view, mSawWindowManager); 101 } 102 103 @Override showActivityChildWindow(String name, IBinder token)104 public void showActivityChildWindow(String name, IBinder token) throws RemoteException { 105 View view = getView(mService); 106 LayoutParams params = newOverlayLayoutParams(name, LayoutParams.TYPE_APPLICATION); 107 params.token = token; 108 mMainHandler.post(() -> mWindowManager.addView(view, params)); 109 mViewManagers.put(view, mWindowManager); 110 } 111 removeOverlays()112 public void removeOverlays() { 113 mService.removeOverlays(); 114 } 115 } 116 removeOverlays()117 private void removeOverlays() { 118 synchronized (mViewManagers) { 119 for (View view : mViewManagers.keySet()) { 120 mViewManagers.get(view).removeView(view); 121 } 122 mViewManagers.clear(); 123 } 124 mMainHandler.post(() -> { 125 if (mToast != null) { 126 mToast.cancel(); 127 } 128 }); 129 } 130 getContextForSaw(Context context)131 private static Context getContextForSaw(Context context) { 132 DisplayManager displayManager = context.getSystemService(DisplayManager.class); 133 Display display = displayManager.getDisplay(DEFAULT_DISPLAY); 134 Context displayContext = context.createDisplayContext(display); 135 return displayContext.createWindowContext(LayoutParams.TYPE_APPLICATION_OVERLAY, null); 136 } 137 getView(Context context)138 private static View getView(Context context) { 139 View view = new View(context); 140 view.setBackgroundColor(BACKGROUND_COLOR); 141 return view; 142 } 143 newOverlayLayoutParams(String windowName, int type)144 private static LayoutParams newOverlayLayoutParams(String windowName, int type) { 145 LayoutParams params = new LayoutParams( 146 LayoutParams.MATCH_PARENT, 147 LayoutParams.MATCH_PARENT, 148 type, 149 LayoutParams.FLAG_NOT_TOUCHABLE | LayoutParams.FLAG_NOT_FOCUSABLE, 150 PixelFormat.TRANSLUCENT); 151 params.setTitle(windowName); 152 return params; 153 } 154 } 155