1 /*
2  * Copyright (C) 2017 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.view.inputmethod.cts.util;
18 
19 import android.app.Service;
20 import android.content.Intent;
21 import android.graphics.Color;
22 import android.graphics.PixelFormat;
23 import android.graphics.drawable.ColorDrawable;
24 import android.os.Handler;
25 import android.os.IBinder;
26 import android.os.Looper;
27 import android.os.ResultReceiver;
28 import android.view.WindowManager;
29 import android.widget.TextView;
30 
31 import androidx.annotation.BinderThread;
32 import androidx.annotation.MainThread;
33 import androidx.annotation.Nullable;
34 
35 public final class WindowFocusStealerService extends Service {
36 
37     @Nullable
38     private TextView mCustomView;
39 
40     private final class BinderService extends IWindowFocusStealer.Stub {
41         @BinderThread
42         @Override
stealWindowFocus(IBinder parentAppWindowToken, ResultReceiver resultReceiver)43         public void stealWindowFocus(IBinder parentAppWindowToken, ResultReceiver resultReceiver) {
44             mMainHandler.post(() -> handleStealWindowFocus(parentAppWindowToken, resultReceiver));
45         }
46     }
47 
48     private final Handler mMainHandler = new Handler(Looper.getMainLooper());
49 
50     @Override
onBind(Intent intent)51     public IBinder onBind(Intent intent) {
52         return new BinderService();
53     }
54 
55     @Override
onUnbind(Intent intent)56     public boolean onUnbind(Intent intent) {
57         handleReset();
58         return false;
59     }
60 
61     @MainThread
handleStealWindowFocus( IBinder parentAppWindowToken, ResultReceiver resultReceiver)62     public void handleStealWindowFocus(
63             IBinder parentAppWindowToken, ResultReceiver resultReceiver) {
64         handleReset();
65 
66         mCustomView = new TextView(this) {
67             private boolean mWindowInitiallyFocused = false;
68             /**
69              * {@inheritDoc}
70              */
71             @Override
72             public void onWindowFocusChanged(boolean hasWindowFocus) {
73                 if (!mWindowInitiallyFocused && hasWindowFocus) {
74                     mWindowInitiallyFocused = true;
75                     resultReceiver.send(0, null);
76                 }
77             }
78         };
79         mCustomView.setText("Popup");
80         mCustomView.setBackground(new ColorDrawable(Color.CYAN));
81         mCustomView.setElevation(0.5f);
82 
83         WindowManager mWm = getSystemService(WindowManager.class);
84         WindowManager.LayoutParams params = new WindowManager.LayoutParams(
85                 150, 150, 10, 10,
86                 WindowManager.LayoutParams.TYPE_APPLICATION_PANEL,
87                 WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
88                         | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
89                 PixelFormat.OPAQUE);
90         params.packageName = getPackageName();
91         params.token = parentAppWindowToken;
92 
93         mWm.addView(mCustomView, params);
94     }
95 
96     @MainThread
handleReset()97     public void handleReset() {
98         if (mCustomView != null) {
99             getSystemService(WindowManager.class).removeView(mCustomView);
100             mCustomView = null;
101         }
102     }
103 
104     @MainThread
onDestroy()105     public void onDestroy() {
106         super.onDestroy();
107         handleReset();
108     }
109 
110 }
111