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 */
16package com.android.coretests.apps.bstatstestapp;
17
18import android.R;
19import android.app.Notification;
20import android.app.NotificationChannel;
21import android.app.NotificationManager;
22import android.app.Service;
23import android.content.Intent;
24import android.graphics.Color;
25import android.graphics.Point;
26import android.os.Handler;
27import android.os.IBinder;
28import android.os.Process;
29import android.os.RemoteException;
30import android.util.Log;
31import android.view.Gravity;
32import android.view.View;
33import android.view.ViewGroup;
34import android.view.WindowManager;
35
36import java.util.concurrent.CountDownLatch;
37import java.util.concurrent.TimeUnit;
38
39public class TestService extends Service {
40    private static final String TAG = TestService.class.getSimpleName();
41
42    private static final int FLAG_START_FOREGROUND = 1;
43
44    private static final String NOTIFICATION_CHANNEL_ID = TAG;
45    private static final int NOTIFICATION_ID = 42;
46
47    private static final int TIMEOUT_OVERLAY_SEC = 2;
48
49    private View mOverlay;
50
51    @Override
52    public void onCreate() {
53        Log.d(TAG, "onCreate called. myUid=" + Process.myUid());
54    }
55
56    @Override
57    public int onStartCommand(Intent intent, int flags, int startId) {
58        Log.d(TAG, "onStartCommand called. myUid=" + Process.myUid());
59        if (intent != null && (intent.getFlags() & FLAG_START_FOREGROUND) != 0) {
60            startForeground();
61        }
62        notifyServiceLaunched(intent);
63        return START_STICKY;
64    }
65
66    @Override
67    public IBinder onBind(Intent intent) {
68        Log.d(TAG, "onBind called. myUid=" + Process.myUid());
69        return null;
70    }
71
72    @Override
73    public void onDestroy() {
74        Log.d(TAG, "onDestroy called. myUid=" + Process.myUid());
75        removeOverlays();
76    }
77
78    private void notifyServiceLaunched(Intent intent) {
79        Common.notifyLaunched(intent, mReceiver.asBinder(), TAG);
80    }
81
82    private void startForeground() {
83        final NotificationManager noMan = getSystemService(NotificationManager.class);
84        noMan.createNotificationChannel(new NotificationChannel(
85                NOTIFICATION_CHANNEL_ID, NOTIFICATION_CHANNEL_ID,
86                NotificationManager.IMPORTANCE_DEFAULT));
87        Log.d(TAG, "Starting foreground. myUid=" + Process.myUid());
88        startForeground(NOTIFICATION_ID,
89                new Notification.Builder(this, NOTIFICATION_CHANNEL_ID)
90                        .setSmallIcon(R.drawable.ic_dialog_alert)
91                        .build());
92    }
93
94    private void removeOverlays() {
95        if (mOverlay != null) {
96            final WindowManager wm = TestService.this.getSystemService(WindowManager.class);
97            wm.removeView(mOverlay);
98            mOverlay = null;
99        }
100    }
101
102    private BaseCmdReceiver mReceiver = new BaseCmdReceiver() {
103        @Override
104        public void doSomeWork(int durationMs) {
105            Common.doSomeWork(durationMs);
106        }
107
108        @Override
109        public void showApplicationOverlay() throws RemoteException {
110            final WindowManager wm = TestService.this.getSystemService(WindowManager.class);
111            final Point size = new Point();
112            wm.getDefaultDisplay().getSize(size);
113
114            final WindowManager.LayoutParams wmlp = new WindowManager.LayoutParams(
115                    WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
116                    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
117                            | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
118                            | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
119            wmlp.width = size.x / 2;
120            wmlp.height = size.y / 2;
121            wmlp.gravity = Gravity.CENTER | Gravity.LEFT;
122            wmlp.setTitle(TAG);
123
124            final ViewGroup.LayoutParams vglp = new ViewGroup.LayoutParams(
125                    ViewGroup.LayoutParams.MATCH_PARENT,
126                    ViewGroup.LayoutParams.MATCH_PARENT);
127
128            mOverlay = new View(TestService.this);
129            mOverlay.setBackgroundColor(Color.GREEN);
130            mOverlay.setLayoutParams(vglp);
131
132            final CountDownLatch latch = new CountDownLatch(1);
133            final Handler handler = new Handler(TestService.this.getMainLooper());
134            handler.post(() -> {
135                wm.addView(mOverlay, wmlp);
136                latch.countDown();
137            });
138            try {
139                if (!latch.await(TIMEOUT_OVERLAY_SEC, TimeUnit.SECONDS)) {
140                    throw new RemoteException("Timed out waiting for the overlay");
141                }
142            } catch (InterruptedException e) {
143                throw new RemoteException("Error while adding overlay: " + e.toString());
144            }
145            Log.d(TAG, "Overlay displayed, myUid=" + Process.myUid());
146        }
147
148        @Override
149        public void finishHost() {
150            removeOverlays();
151            stopSelf();
152        }
153    };
154}
155