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

Commit f4f7063e authored by Tyler Gunn's avatar Tyler Gunn Committed by Gerrit Code Review
Browse files

Merge "Call Diagnostic Service implementation"

parents 0e44b583 16f5dd95
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -69,4 +69,8 @@
    <!-- When true, the options in the call blocking settings to block restricted and unknown
         callers are combined into a single toggle. -->
    <bool name="combine_options_to_block_restricted_and_unknown_callers">true</bool>

    <!-- When set, Telecom will attempt to bind to the {@link CallDiagnosticService} implementation
         defined by the app with this package name. -->
    <string name="call_diagnostic_service_package_name"></string>
</resources>
+99 −0
Original line number Diff line number Diff line
@@ -37,11 +37,13 @@ import android.os.Trace;
import android.os.UserHandle;
import android.provider.CallLog;
import android.provider.ContactsContract.Contacts;
import android.telecom.BluetoothCallQualityReport;
import android.telecom.CallAudioState;
import android.telecom.CallerInfo;
import android.telecom.Conference;
import android.telecom.Connection;
import android.telecom.ConnectionService;
import android.telecom.DiagnosticCall;
import android.telecom.DisconnectCause;
import android.telecom.GatewayInfo;
import android.telecom.InCallService;
@@ -156,6 +158,8 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable,
                                 Bundle extras, boolean isLegacy);
        void onHandoverFailed(Call call, int error);
        void onHandoverComplete(Call call);
        void onBluetoothCallQualityReport(Call call, BluetoothCallQualityReport report);
        void onReceivedDeviceToDeviceMessage(Call call, int messageType, int messageValue);
    }

    public abstract static class ListenerBase implements Listener {
@@ -244,6 +248,10 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable,
        public void onHandoverFailed(Call call, int error) {}
        @Override
        public void onHandoverComplete(Call call) {}
        @Override
        public void onBluetoothCallQualityReport(Call call, BluetoothCallQualityReport report) {}
        @Override
        public void onReceivedDeviceToDeviceMessage(Call call, int messageType, int messageValue) {}
    }

    private final CallerInfoLookupHelper.OnQueryCompleteListener mCallerInfoQueryListener =
@@ -646,6 +654,13 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable,
     */
    private String mCallScreeningComponentName;

    /**
     * When {@code true} indicates this call originated from a SIM-based {@link PhoneAccount}.
     * A sim-based {@link PhoneAccount} is one with {@link PhoneAccount#CAPABILITY_SIM_SUBSCRIPTION}
     * set.
     */
    private boolean mIsSimCall;

    /**
     * Persists the specified parameters and initializes the new instance.
     * @param context The context.
@@ -1077,6 +1092,10 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable,
        }
    }

    public void handleOverrideDisconnectMessage(@Nullable CharSequence message) {

    }

    /**
     * Sets the call state. Although there exists the notion of appropriate state transitions
     * (see {@link CallState}), in practice those expectations break down when cellular systems
@@ -1703,6 +1722,7 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable,
        PhoneAccountRegistrar phoneAccountRegistrar = mCallsManager.getPhoneAccountRegistrar();
        boolean isWorkCall = false;
        boolean isCallRecordingToneSupported = false;
        boolean isSimCall = false;
        PhoneAccount phoneAccount =
                phoneAccountRegistrar.getPhoneAccountUnchecked(mTargetPhoneAccountHandle);
        if (phoneAccount != null) {
@@ -1720,9 +1740,11 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable,
                    PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION) && phoneAccount.getExtras() != null
                    && phoneAccount.getExtras().getBoolean(
                    PhoneAccount.EXTRA_PLAY_CALL_RECORDING_TONE, false));
            isSimCall = phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION);
        }
        mIsWorkCall = isWorkCall;
        mUseCallRecordingTone = isCallRecordingToneSupported;
        mIsSimCall = isSimCall;
    }

    /**
@@ -2952,6 +2974,14 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable,
                }
                requestHandover(phoneAccountHandle, videoState, handoverExtrasBundle, true);
            } else {
                // Relay bluetooth call quality reports to the call diagnostic service.
                if (BluetoothCallQualityReport.EVENT_BLUETOOTH_CALL_QUALITY_REPORT.equals(event)
                        && extras.containsKey(
                        BluetoothCallQualityReport.EXTRA_BLUETOOTH_CALL_QUALITY_REPORT)) {
                    notifyBluetoothCallQualityReport(extras.getParcelable(
                            BluetoothCallQualityReport.EXTRA_BLUETOOTH_CALL_QUALITY_REPORT
                    ));
                }
                Log.addEvent(this, LogUtils.Events.CALL_EVENT, event);
                mConnectionService.sendCallEvent(this, event, extras);
            }
@@ -2961,6 +2991,17 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable,
        }
    }

    /**
     * Notifies listeners when a bluetooth quality report is received.
     * @param report The bluetooth quality report.
     */
    void notifyBluetoothCallQualityReport(@NonNull BluetoothCallQualityReport report) {
        Log.addEvent(this, LogUtils.Events.BT_QUALITY_REPORT, "choppy=" + report.isChoppyVoice());
        for (Listener l : mListeners) {
            l.onBluetoothCallQualityReport(this, report);
        }
    }

    /**
     * Initiates a handover of this Call to the {@link ConnectionService} identified
     * by destAcct.
@@ -3691,6 +3732,17 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable,
            for (Listener l : mListeners) {
                l.onCallSwitchFailed(this);
            }
        } else if (Connection.EVENT_DEVICE_TO_DEVICE_MESSAGE.equals(event)
                && extras != null && extras.containsKey(
                Connection.EXTRA_DEVICE_TO_DEVICE_MESSAGE_TYPE)
                && extras.containsKey(Connection.EXTRA_DEVICE_TO_DEVICE_MESSAGE_VALUE)) {
            // Relay an incoming D2D message to interested listeners; most notably the
            // CallDiagnosticService.
            int messageType = extras.getInt(Connection.EXTRA_DEVICE_TO_DEVICE_MESSAGE_TYPE);
            int messageValue = extras.getInt(Connection.EXTRA_DEVICE_TO_DEVICE_MESSAGE_VALUE);
            for (Listener l : mListeners) {
                l.onReceivedDeviceToDeviceMessage(this, messageType, messageValue);
            }
        } else {
            for (Listener l : mListeners) {
                l.onConnectionEvent(this, event, extras);
@@ -3891,6 +3943,44 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable,
        }
    }

    /**
     * Sends a device to device message to the other part of the call.
     * @param message the message type to send.
     * @param value the value for the message.
     */
    public void sendDeviceToDeviceMessage(@DiagnosticCall.MessageType int message, int value) {
        Log.i(this, "sendDeviceToDeviceMessage; callId=%s, msg=%d/%d", getId(), message, value);
        Bundle extras = new Bundle();
        extras.putInt(Connection.EXTRA_DEVICE_TO_DEVICE_MESSAGE_TYPE, message);
        extras.putInt(Connection.EXTRA_DEVICE_TO_DEVICE_MESSAGE_VALUE, value);
        // Send to the connection service.
        sendCallEvent(Connection.EVENT_DEVICE_TO_DEVICE_MESSAGE, extras);
    }

    /**
     * Signals to the Dialer app to start displaying a diagnostic message.
     * @param messageId a unique ID for the message to display.
     * @param message the message to display.
     */
    public void displayDiagnosticMessage(int messageId, @NonNull CharSequence message) {
        Bundle extras = new Bundle();
        extras.putInt(android.telecom.Call.EXTRA_DIAGNOSTIC_MESSAGE_ID, messageId);
        extras.putCharSequence(android.telecom.Call.EXTRA_DIAGNOSTIC_MESSAGE, message);
        // Send to the dialer.
        onConnectionEvent(android.telecom.Call.EVENT_DISPLAY_DIAGNOSTIC_MESSAGE, extras);
    }

    /**
     * Signals to the Dialer app to stop displaying a diagnostic message.
     * @param messageId a unique ID for the message to clear.
     */
    public void clearDiagnosticMessage(int messageId) {
        Bundle extras = new Bundle();
        extras.putInt(android.telecom.Call.EXTRA_DIAGNOSTIC_MESSAGE_ID, messageId);
        // Send to the dialer.
        onConnectionEvent(android.telecom.Call.EVENT_CLEAR_DIAGNOSTIC_MESSAGE, extras);
    }

    /**
     * Remaps the call direction as indicated by an {@link android.telecom.Call.Details} direction
     * constant to the constants (e.g. {@link #CALL_DIRECTION_INCOMING}) used in this call class.
@@ -3977,4 +4067,13 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable,
            }
        }
    }

    /**
     * @return {@code true} when this call originated from a SIM-based {@link PhoneAccount}.
     * A sim-based {@link PhoneAccount} is one with {@link PhoneAccount#CAPABILITY_SIM_SUBSCRIPTION}
     * set.
     */
    public boolean isSimCall() {
        return mIsSimCall;
    }
}
+132 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.telecom;

import android.annotation.NonNull;
import android.os.Binder;
import android.os.RemoteException;
import android.telecom.CallDiagnosticService;
import android.telecom.DiagnosticCall;
import android.telecom.Log;

import com.android.internal.telecom.ICallDiagnosticServiceAdapter;
import com.android.internal.telecom.IInCallAdapter;

/**
 * Adapter class used to provide a path for messages FROM a {@link CallDiagnosticService} back to
 * the telecom stack.
 */
public class CallDiagnosticServiceAdapter extends ICallDiagnosticServiceAdapter.Stub {
    public interface TelecomAdapter {
        void displayDiagnosticMessage(String callId, int messageId, CharSequence message);
        void clearDiagnosticMessage(String callId, int messageId);
        void sendDeviceToDeviceMessage(String callId, @DiagnosticCall.MessageType int message,
                int value);
        void overrideDisconnectMessage(String callId, CharSequence message);
    }

    private final TelecomAdapter mTelecomAdapter;
    private final String mOwnerPackageName;
    private final String mOwnerPackageAbbreviation;
    private final TelecomSystem.SyncRoot mLock;

    CallDiagnosticServiceAdapter(@NonNull TelecomAdapter telecomAdapter,
            @NonNull String ownerPackageName, @NonNull TelecomSystem.SyncRoot lock) {
        mTelecomAdapter = telecomAdapter;
        mOwnerPackageName = ownerPackageName;
        mOwnerPackageAbbreviation = Log.getPackageAbbreviation(ownerPackageName);
        mLock = lock;
    }

    @Override
    public void displayDiagnosticMessage(String callId, int messageId, CharSequence message)
            throws RemoteException {
        try {
            Log.startSession("CDSA.dDM", mOwnerPackageAbbreviation);
            long token = Binder.clearCallingIdentity();
            try {
                synchronized (mLock) {
                    Log.i(this, "displayDiagnosticMessage; callId=%s, msg=%d/%s", callId, messageId,
                            message);
                    mTelecomAdapter.displayDiagnosticMessage(callId, messageId, message);
                }
            } finally {
                Binder.restoreCallingIdentity(token);
            }
        } finally {
            Log.endSession();
        }
    }

    @Override
    public void clearDiagnosticMessage(String callId, int messageId) throws RemoteException {
        try {
            Log.startSession("CDSA.cDM", mOwnerPackageAbbreviation);
            long token = Binder.clearCallingIdentity();
            try {
                synchronized (mLock) {
                    Log.i(this, "clearDiagnosticMessage; callId=%s, msg=%d", callId, messageId);
                    mTelecomAdapter.clearDiagnosticMessage(callId, messageId);
                }
            } finally {
                Binder.restoreCallingIdentity(token);
            }
        } finally {
            Log.endSession();
        }
    }

    @Override
    public void sendDeviceToDeviceMessage(String callId, @DiagnosticCall.MessageType int message,
            int value)
            throws RemoteException {
        try {
            Log.startSession("CDSA.sDTDM", mOwnerPackageAbbreviation);
            long token = Binder.clearCallingIdentity();
            try {
                synchronized (mLock) {
                    Log.i(this, "sendDeviceToDeviceMessage; callId=%s, msg=%d/%d", callId, message,
                            value);
                    mTelecomAdapter.sendDeviceToDeviceMessage(callId, message, value);
                }
            } finally {
                Binder.restoreCallingIdentity(token);
            }
        } finally {
            Log.endSession();
        }
    }

    @Override
    public void overrideDisconnectMessage(String callId, CharSequence message)
            throws RemoteException {
        try {
            Log.startSession("CDSA.oDM", mOwnerPackageAbbreviation);
            long token = Binder.clearCallingIdentity();
            try {
                synchronized (mLock) {
                    Log.i(this, "overrideDisconnectMessage; callId=%s, msg=%s", callId, message);
                    mTelecomAdapter.overrideDisconnectMessage(callId, message);
                }
            } finally {
                Binder.restoreCallingIdentity(token);
            }
        } finally {
            Log.endSession();
        }
    }
}
+654 −0

File added.

Preview size limit exceeded, changes collapsed.

+34 −15
Original line number Diff line number Diff line
@@ -332,6 +332,7 @@ public class CallsManager extends Call.ListenerBase
    private final ConnectionServiceRepository mConnectionServiceRepository;
    private final DtmfLocalTonePlayer mDtmfLocalTonePlayer;
    private final InCallController mInCallController;
    private final CallDiagnosticServiceController mCallDiagnosticServiceController;
    private final CallAudioManager mCallAudioManager;
    private final CallRecordingTonePlayer mCallRecordingTonePlayer;
    private RespondViaSmsManager mRespondViaSmsManager;
@@ -487,6 +488,7 @@ public class CallsManager extends Call.ListenerBase
            CallAudioRouteStateMachine.Factory callAudioRouteStateMachineFactory,
            CallAudioModeStateMachine.Factory callAudioModeStateMachineFactory,
            InCallControllerFactory inCallControllerFactory,
            CallDiagnosticServiceController callDiagnosticServiceController,
            RoleManagerAdapter roleManagerAdapter,
            ToastFactory toastFactory) {
        mContext = context;
@@ -543,6 +545,7 @@ public class CallsManager extends Call.ListenerBase
        mInCallController = inCallControllerFactory.create(context, mLock, this,
                systemStateHelper, defaultDialerCache, mTimeoutsAdapter,
                emergencyCallHelper);
        mCallDiagnosticServiceController = callDiagnosticServiceController;
        mRinger = new Ringer(playerFactory, context, systemSettingsUtil, asyncRingtonePlayer,
                ringtoneFactory, systemVibrator,
                new Ringer.VibrationEffectProxy(), mInCallController);
@@ -572,6 +575,7 @@ public class CallsManager extends Call.ListenerBase
        mListeners.add(mCallLogManager);
        mListeners.add(mPhoneStateBroadcaster);
        mListeners.add(mInCallController);
        mListeners.add(mCallDiagnosticServiceController);
        mListeners.add(mCallAudioManager);
        mListeners.add(mCallRecordingTonePlayer);
        mListeners.add(missedCallNotifier);
@@ -622,6 +626,10 @@ public class CallsManager extends Call.ListenerBase
        return mRoleManagerAdapter;
    }

    public CallDiagnosticServiceController getCallDiagnosticServiceController() {
        return mCallDiagnosticServiceController;
    }

    @Override
    public void onSuccessfulOutgoingCall(Call call, int callState) {
        Log.v(this, "onSuccessfulOutgoingCall, %s", call);
@@ -3631,7 +3639,16 @@ public class CallsManager extends Call.ListenerBase
                Trace.beginSection("onCallStateChanged");

                maybeHandleHandover(call, newState);
                notifyCallStateChanged(call, oldState, newState);

                Trace.endSection();
            } else {
                Log.i(this, "failed in setting the state to new state");
            }
        }
    }

    private void notifyCallStateChanged(Call call, int oldState, int newState) {
        // Only broadcast state change for calls that are being tracked.
        if (mCalls.contains(call)) {
            updateCanAddCall();
@@ -3647,11 +3664,6 @@ public class CallsManager extends Call.ListenerBase
                }
            }
        }
                Trace.endSection();
            } else {
                Log.i(this, "failed in setting the state to new state");
            }
        }
    }

    /**
@@ -4691,6 +4703,13 @@ public class CallsManager extends Call.ListenerBase
            pw.decreaseIndent();
        }

        if (mCallDiagnosticServiceController != null) {
            pw.println("mCallDiagnosticServiceController:");
            pw.increaseIndent();
            mCallDiagnosticServiceController.dump(pw);
            pw.decreaseIndent();
        }

        if (mDefaultDialerCache != null) {
            pw.println("mDefaultDialerCache:");
            pw.increaseIndent();
Loading