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