1 /* 2 * Copyright (C) 2022 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.example.android.sampleinputmethodaccessibilityservice; 18 19 import android.content.Context; 20 import android.graphics.PixelFormat; 21 import android.view.Gravity; 22 import android.view.View; 23 import android.view.WindowManager; 24 import android.view.accessibility.AccessibilityEvent; 25 import android.widget.FrameLayout; 26 27 import androidx.annotation.ColorInt; 28 import androidx.annotation.NonNull; 29 30 final class OverlayWindowBuilder { 31 @NonNull 32 private final View mContentView; 33 private int mWidth = WindowManager.LayoutParams.WRAP_CONTENT; 34 private int mHeight = WindowManager.LayoutParams.WRAP_CONTENT; 35 private int mGravity = Gravity.NO_GRAVITY; 36 private int mRelX = 0; 37 private int mRelY = 0; 38 private Integer mBackgroundColor = null; 39 private boolean mShown = false; 40 OverlayWindowBuilder(@onNull View contentView)41 private OverlayWindowBuilder(@NonNull View contentView) { 42 mContentView = contentView; 43 } 44 from(@onNull View contentView)45 static OverlayWindowBuilder from(@NonNull View contentView) { 46 return new OverlayWindowBuilder(contentView); 47 } 48 setSize(int width, int height)49 OverlayWindowBuilder setSize(int width, int height) { 50 mWidth = width; 51 mHeight = height; 52 return this; 53 } 54 setGravity(int gravity)55 OverlayWindowBuilder setGravity(int gravity) { 56 mGravity = gravity; 57 return this; 58 } 59 setRelativePosition(int relX, int relY)60 OverlayWindowBuilder setRelativePosition(int relX, int relY) { 61 mRelX = relX; 62 mRelY = relY; 63 return this; 64 } 65 setBackgroundColor(@olorInt int color)66 OverlayWindowBuilder setBackgroundColor(@ColorInt int color) { 67 mBackgroundColor = color; 68 return this; 69 } 70 show()71 void show() { 72 if (mShown) { 73 throw new UnsupportedOperationException("show() can be called only once."); 74 } 75 76 final Context context = mContentView.getContext(); 77 final WindowManager windowManager = context.getSystemService(WindowManager.class); 78 79 final FrameLayout contentFrame = new FrameLayout(context) { 80 @Override 81 public boolean requestSendAccessibilityEvent(View view, AccessibilityEvent event) { 82 return false; 83 } 84 85 @Override 86 public void sendAccessibilityEventUnchecked(AccessibilityEvent event) { 87 } 88 }; 89 if (mBackgroundColor != null) { 90 contentFrame.setBackgroundColor(mBackgroundColor); 91 } 92 contentFrame.setOnTouchListener(new DragToMoveTouchListener((dx, dy) -> { 93 final WindowManager.LayoutParams lp = 94 (WindowManager.LayoutParams) contentFrame.getLayoutParams(); 95 lp.x += dx; 96 lp.y += dy; 97 windowManager.updateViewLayout(contentFrame, lp); 98 })); 99 contentFrame.addView(mContentView); 100 final WindowManager.LayoutParams params = new WindowManager.LayoutParams( 101 mWidth, mHeight, 102 WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY, 103 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN 104 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, 105 PixelFormat.TRANSLUCENT); 106 params.gravity = mGravity; 107 params.x = mRelX; 108 params.y = mRelY; 109 windowManager.addView(contentFrame, params); 110 mShown = true; 111 } 112 } 113