Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b614d4b1 authored by Grace Jia's avatar Grace Jia Committed by Automerger Merge Worker
Browse files

Hold only notification info in VoipCallMonitor. am: 9e31e900

parents 3e473019 9e31e900
Loading
Loading
Loading
Loading
+49 −40
Original line number Diff line number Diff line
@@ -31,7 +31,6 @@ import android.os.UserHandle;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.telecom.Log;
import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;

import com.android.internal.annotations.VisibleForTesting;
@@ -52,11 +51,11 @@ import java.util.concurrent.CompletableFuture;

public class VoipCallMonitor extends CallsManagerListenerBase {

    private final List<Call> mPendingCalls;
    private final List<Call> mNotificationPendingCalls;
    // Same notification may be passed as different object in onNotificationPosted and
    // onNotificationRemoved. Use its string as key to cache ongoing notifications.
    private final Map<String, Call> mNotifications;
    private final Map<PhoneAccountHandle, Set<Call>> mPhoneAccountHandleListMap;
    private final Map<NotificationInfo, Call> mNotificationInfoToCallMap;
    private final Map<PhoneAccountHandle, Set<Call>> mAccountHandleToCallMap;
    private ActivityManagerInternal mActivityManagerInternal;
    private final Map<PhoneAccountHandle, ServiceConnection> mServices;
    private NotificationListenerService mNotificationListener;
@@ -64,7 +63,7 @@ public class VoipCallMonitor extends CallsManagerListenerBase {
    private final HandlerThread mHandlerThread;
    private final Handler mHandler;
    private final Context mContext;
    private List<StatusBarNotification> mPendingSBN;
    private List<NotificationInfo> mCachedNotifications;
    private TelecomSystem.SyncRoot mSyncRoot;

    public VoipCallMonitor(Context context, TelecomSystem.SyncRoot lock) {
@@ -73,11 +72,11 @@ public class VoipCallMonitor extends CallsManagerListenerBase {
        mHandlerThread = new HandlerThread(this.getClass().getSimpleName());
        mHandlerThread.start();
        mHandler = new Handler(mHandlerThread.getLooper());
        mPendingCalls = new ArrayList<>();
        mPendingSBN = new ArrayList<>();
        mNotifications = new HashMap<>();
        mNotificationPendingCalls = new ArrayList<>();
        mCachedNotifications = new ArrayList<>();
        mNotificationInfoToCallMap = new HashMap<>();
        mServices = new HashMap<>();
        mPhoneAccountHandleListMap = new HashMap<>();
        mAccountHandleToCallMap = new HashMap<>();
        mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);

        mNotificationListener = new NotificationListenerService() {
@@ -85,19 +84,21 @@ public class VoipCallMonitor extends CallsManagerListenerBase {
            public void onNotificationPosted(StatusBarNotification sbn) {
                synchronized (mLock) {
                    if (sbn.getNotification().isStyle(Notification.CallStyle.class)) {
                        NotificationInfo info = new NotificationInfo(sbn.getPackageName(),
                                sbn.getUser());
                        boolean sbnMatched = false;
                        for (Call call : mPendingCalls) {
                            if (notificationMatchedCall(sbn, call)) {
                                mPendingCalls.remove(call);
                                mNotifications.put(sbn.toString(), call);
                        for (Call call : mNotificationPendingCalls) {
                            if (info.matchesCall(call)) {
                                mNotificationPendingCalls.remove(call);
                                mNotificationInfoToCallMap.put(info, call);
                                sbnMatched = true;
                                break;
                            }
                        }
                        if (!sbnMatched) {
                            // notification may posted before we started to monitor the call, cache
                            // notification may post before we started to monitor the call, cache
                            // this notification and try to match it later with new added call.
                            mPendingSBN.add(sbn);
                            mCachedNotifications.add(info);
                        }
                    }
                }
@@ -106,13 +107,16 @@ public class VoipCallMonitor extends CallsManagerListenerBase {
            @Override
            public void onNotificationRemoved(StatusBarNotification sbn) {
                synchronized (mLock) {
                    mPendingSBN.remove(sbn);
                    if (mNotifications.isEmpty()) {
                    NotificationInfo info = new NotificationInfo(sbn.getPackageName(),
                            sbn.getUser());
                    mCachedNotifications.remove(info);
                    if (mNotificationInfoToCallMap.isEmpty()) {
                        return;
                    }
                    Call call = mNotifications.getOrDefault(sbn.toString(), null);
                    Call call = mNotificationInfoToCallMap.getOrDefault(info, null);
                    if (call != null) {
                        mNotifications.remove(sbn.toString(), call);
                        // TODO: fix potential bug for multiple calls of same voip app.
                        mNotificationInfoToCallMap.remove(info, call);
                        stopFGSDelegation(call);
                    }
                }
@@ -147,7 +151,7 @@ public class VoipCallMonitor extends CallsManagerListenerBase {

        synchronized (mLock) {
            PhoneAccountHandle phoneAccountHandle = call.getTargetPhoneAccount();
            Set<Call> callList = mPhoneAccountHandleListMap.computeIfAbsent(phoneAccountHandle,
            Set<Call> callList = mAccountHandleToCallMap.computeIfAbsent(phoneAccountHandle,
                    k -> new HashSet<>());
            callList.add(call);

@@ -169,7 +173,7 @@ public class VoipCallMonitor extends CallsManagerListenerBase {
        synchronized (mLock) {
            stopMonitorWorks(call);
            PhoneAccountHandle phoneAccountHandle = call.getTargetPhoneAccount();
            Set<Call> callList = mPhoneAccountHandleListMap.computeIfAbsent(phoneAccountHandle,
            Set<Call> callList = mAccountHandleToCallMap.computeIfAbsent(phoneAccountHandle,
                    k -> new HashSet<>());
            callList.remove(call);

@@ -218,13 +222,13 @@ public class VoipCallMonitor extends CallsManagerListenerBase {
        synchronized (mLock) {
            Log.i(this, "stopFGSDelegation of call %s", call);
            PhoneAccountHandle handle = call.getTargetPhoneAccount();
            Set<Call> calls = mPhoneAccountHandleListMap.get(handle);
            Set<Call> calls = mAccountHandleToCallMap.get(handle);
            if (calls != null) {
                for (Call c : calls) {
                    stopMonitorWorks(c);
                }
            }
            mPhoneAccountHandleListMap.remove(handle);
            mAccountHandleToCallMap.remove(handle);

            if (mActivityManagerInternal != null) {
                ServiceConnection fgsConnection = mServices.get(handle);
@@ -247,26 +251,26 @@ public class VoipCallMonitor extends CallsManagerListenerBase {
    private void startMonitorNotification(Call call) {
        synchronized (mLock) {
            boolean sbnMatched = false;
            for (StatusBarNotification sbn : mPendingSBN) {
                if (notificationMatchedCall(sbn, call)) {
                    mPendingSBN.remove(sbn);
                    mNotifications.put(sbn.toString(), call);
            for (NotificationInfo info : mCachedNotifications) {
                if (info.matchesCall(call)) {
                    mCachedNotifications.remove(info);
                    mNotificationInfoToCallMap.put(info, call);
                    sbnMatched = true;
                    break;
                }
            }
            if (!sbnMatched) {
                // Only continue to
                mPendingCalls.add(call);
                mNotificationPendingCalls.add(call);
                CompletableFuture<Void> future = new CompletableFuture<>();
                mHandler.postDelayed(() -> future.complete(null), 5000L);
                future.thenComposeAsync(
                        (x) -> {
                            if (mPendingCalls.contains(call)) {
                            if (mNotificationPendingCalls.contains(call)) {
                                Log.i(this, "Notification for voip-call %s haven't "
                                        + "posted in time, stop delegation.", call.getId());
                                stopFGSDelegation(call);
                                mPendingCalls.remove(call);
                                mNotificationPendingCalls.remove(call);
                                return null;
                            }
                            return null;
@@ -276,7 +280,7 @@ public class VoipCallMonitor extends CallsManagerListenerBase {
    }

    private void stopMonitorNotification(Call call) {
        mPendingCalls.remove(call);
        mNotificationPendingCalls.remove(call);
    }

    @VisibleForTesting
@@ -289,15 +293,20 @@ public class VoipCallMonitor extends CallsManagerListenerBase {
        mNotificationListener = listener;
    }

    private boolean notificationMatchedCall(StatusBarNotification sbn, Call call) {
        String packageName = sbn.getPackageName();
        UserHandle userHandle = sbn.getUser();
        PhoneAccountHandle accountHandle = call.getTargetPhoneAccount();
    private class NotificationInfo {
        private String mPackageName;
        private UserHandle mUserHandle;

        NotificationInfo(String packageName, UserHandle userHandle) {
            mPackageName = packageName;
            mUserHandle = userHandle;
        }

        return packageName != null &&
                packageName.equals(call.getTargetPhoneAccount()
                        .getComponentName().getPackageName())
                && userHandle != null
                && userHandle.equals(accountHandle.getUserHandle());
        boolean matchesCall(Call call) {
            PhoneAccountHandle accountHandle = call.getTargetPhoneAccount();
            return mPackageName != null && mPackageName.equals(
                   accountHandle.getComponentName().getPackageName())
                    && mUserHandle != null && mUserHandle.equals(accountHandle.getUserHandle());
        }
    }
}