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 com.android.app2;
18 
19 import android.app.Service;
20 import android.content.Intent;
21 import android.graphics.Point;
22 import android.os.Handler;
23 import android.os.IBinder;
24 import android.os.Message;
25 import android.os.Messenger;
26 import android.os.RemoteException;
27 import android.util.Log;
28 import android.view.View;
29 import android.view.WindowManager;
30 import android.widget.TextView;
31 
32 import java.util.LinkedList;
33 
34 import static android.graphics.Color.BLUE;
35 import static android.view.Gravity.LEFT;
36 import static android.view.Gravity.TOP;
37 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
38 import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
39 import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
40 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
41 
42 /** Service for creating and managing alert windows. */
43 public class AlertWindowService extends Service {
44 
45     private static final String TAG = "AlertWindowService";
46     private static final boolean DEBUG = false;
47 
48     public static final int MSG_ADD_ALERT_WINDOW = 1;
49     public static final int MSG_REMOVE_ALERT_WINDOW = 2;
50     public static final int MSG_REMOVE_ALL_ALERT_WINDOWS = 3;
51 
52     public static String NOTIFICATION_MESSENGER_EXTRA =
53             "com.android.app2.AlertWindowService.NOTIFICATION_MESSENGER_EXTRA";
54     public static final int MSG_ON_ALERT_WINDOW_ADDED = 4;
55     public static final int MSG_ON_ALERT_WINDOW_REMOVED = 5;
56 
57     private LinkedList<View> mAlertWindows = new LinkedList<>();
58 
59     private Messenger mOutgoingMessenger = null;
60     private final Messenger mIncomingMessenger = new Messenger(new IncomingHandler());
61 
62     private class IncomingHandler extends Handler {
63         @Override
handleMessage(Message msg)64         public void handleMessage(Message msg) {
65             switch (msg.what) {
66                 case MSG_ADD_ALERT_WINDOW:
67                     addAlertWindow();
68                     break;
69                 case MSG_REMOVE_ALERT_WINDOW:
70                     removeAlertWindow();
71                     break;
72                 case MSG_REMOVE_ALL_ALERT_WINDOWS:
73                     removeAllAlertWindows();
74                     break;
75                 default:
76                     super.handleMessage(msg);
77             }
78         }
79     }
80 
addAlertWindow()81     private void addAlertWindow() {
82         final Point size = new Point();
83         final WindowManager wm = getSystemService(WindowManager.class);
84         wm.getDefaultDisplay().getSize(size);
85 
86         final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
87                 TYPE_APPLICATION_OVERLAY,
88                 FLAG_NOT_FOCUSABLE | FLAG_WATCH_OUTSIDE_TOUCH | FLAG_NOT_TOUCHABLE);
89         params.width = size.x / 3;
90         params.height = size.y / 3;
91         params.gravity = TOP | LEFT;
92 
93         final TextView view = new TextView(this);
94         view.setText("AlertWindowService" + mAlertWindows.size());
95         view.setBackgroundColor(BLUE);
96         wm.addView(view, params);
97         mAlertWindows.add(view);
98 
99         if (DEBUG) Log.e(TAG, "addAlertWindow " + mAlertWindows.size());
100         if (mOutgoingMessenger != null) {
101             try {
102                 mOutgoingMessenger.send(Message.obtain(null, MSG_ON_ALERT_WINDOW_ADDED));
103             } catch (RemoteException e) {
104 
105             }
106         }
107     }
108 
removeAlertWindow()109     private void removeAlertWindow() {
110         if (mAlertWindows.size() == 0) {
111             return;
112         }
113         final WindowManager wm = getSystemService(WindowManager.class);
114         wm.removeView(mAlertWindows.pop());
115 
116         if (DEBUG) Log.e(TAG, "removeAlertWindow " + mAlertWindows.size());
117         if (mOutgoingMessenger != null) {
118             try {
119                 mOutgoingMessenger.send(Message.obtain(null, MSG_ON_ALERT_WINDOW_REMOVED));
120             } catch (RemoteException e) {
121 
122             }
123         }
124     }
125 
removeAllAlertWindows()126     private void removeAllAlertWindows() {
127         while (mAlertWindows.size() > 0) {
128             removeAlertWindow();
129         }
130     }
131 
132     @Override
onBind(Intent intent)133     public IBinder onBind(Intent intent) {
134         if (DEBUG) Log.e(TAG, "onBind");
135         mOutgoingMessenger = intent.getParcelableExtra(NOTIFICATION_MESSENGER_EXTRA);
136         return mIncomingMessenger.getBinder();
137     }
138 
139     @Override
onUnbind(Intent intent)140     public boolean onUnbind(Intent intent) {
141         if (DEBUG) Log.e(TAG, "onUnbind");
142         removeAllAlertWindows();
143         return super.onUnbind(intent);
144     }
145 }
146