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 com.android.systemui.toast;
18 
19 import android.annotation.MainThread;
20 import android.annotation.Nullable;
21 import android.app.INotificationManager;
22 import android.app.ITransientNotificationCallback;
23 import android.content.Context;
24 import android.content.res.Resources;
25 import android.os.IBinder;
26 import android.os.ServiceManager;
27 import android.os.UserHandle;
28 import android.util.Log;
29 import android.view.View;
30 import android.view.accessibility.IAccessibilityManager;
31 import android.widget.ToastPresenter;
32 
33 import com.android.internal.R;
34 import com.android.internal.annotations.VisibleForTesting;
35 import com.android.systemui.SystemUI;
36 import com.android.systemui.statusbar.CommandQueue;
37 
38 import java.util.Objects;
39 
40 import javax.inject.Inject;
41 import javax.inject.Singleton;
42 
43 /**
44  * Controls display of text toasts.
45  */
46 @Singleton
47 public class ToastUI extends SystemUI implements CommandQueue.Callbacks {
48     private static final String TAG = "ToastUI";
49 
50     private final CommandQueue mCommandQueue;
51     private final INotificationManager mNotificationManager;
52     private final IAccessibilityManager mAccessibilityManager;
53     private final int mGravity;
54     private final int mY;
55     @Nullable private ToastPresenter mPresenter;
56     @Nullable private ITransientNotificationCallback mCallback;
57 
58     @Inject
ToastUI(Context context, CommandQueue commandQueue)59     public ToastUI(Context context, CommandQueue commandQueue) {
60         this(context, commandQueue,
61                 INotificationManager.Stub.asInterface(
62                         ServiceManager.getService(Context.NOTIFICATION_SERVICE)),
63                 IAccessibilityManager.Stub.asInterface(
64                         ServiceManager.getService(Context.ACCESSIBILITY_SERVICE)));
65     }
66 
67     @VisibleForTesting
ToastUI(Context context, CommandQueue commandQueue, INotificationManager notificationManager, @Nullable IAccessibilityManager accessibilityManager)68     ToastUI(Context context, CommandQueue commandQueue, INotificationManager notificationManager,
69             @Nullable IAccessibilityManager accessibilityManager) {
70         super(context);
71         mCommandQueue = commandQueue;
72         mNotificationManager = notificationManager;
73         mAccessibilityManager = accessibilityManager;
74         Resources resources = mContext.getResources();
75         mGravity = resources.getInteger(R.integer.config_toastDefaultGravity);
76         mY = resources.getDimensionPixelSize(R.dimen.toast_y_offset);
77     }
78 
79     @Override
start()80     public void start() {
81         mCommandQueue.addCallback(this);
82     }
83 
84     @Override
85     @MainThread
showToast(int uid, String packageName, IBinder token, CharSequence text, IBinder windowToken, int duration, @Nullable ITransientNotificationCallback callback)86     public void showToast(int uid, String packageName, IBinder token, CharSequence text,
87             IBinder windowToken, int duration, @Nullable ITransientNotificationCallback callback) {
88         if (mPresenter != null) {
89             hideCurrentToast();
90         }
91         Context context = mContext.createContextAsUser(UserHandle.getUserHandleForUid(uid), 0);
92         View view = ToastPresenter.getTextToastView(context, text);
93         mCallback = callback;
94         mPresenter = new ToastPresenter(context, mAccessibilityManager, mNotificationManager,
95                 packageName);
96         mPresenter.show(view, token, windowToken, duration, mGravity, 0, mY, 0, 0, mCallback);
97     }
98 
99     @Override
100     @MainThread
hideToast(String packageName, IBinder token)101     public void hideToast(String packageName, IBinder token) {
102         if (mPresenter == null || !Objects.equals(mPresenter.getPackageName(), packageName)
103                 || !Objects.equals(mPresenter.getToken(), token)) {
104             Log.w(TAG, "Attempt to hide non-current toast from package " + packageName);
105             return;
106         }
107         hideCurrentToast();
108     }
109 
110     @MainThread
hideCurrentToast()111     private void hideCurrentToast() {
112         mPresenter.hide(mCallback);
113         mPresenter = null;
114     }
115 }
116