Loading src/com/android/server/telecom/InCallController.java +85 −2 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.server.telecom; import static android.app.AppOpsManager.OPSTR_RECORD_AUDIO; import static android.os.Process.myUid; import android.Manifest; Loading Loading @@ -80,7 +81,8 @@ import java.util.stream.Collectors; * can send updates to the in-call app. This class is created and owned by CallsManager and retains * a binding to the {@link IInCallService} (implemented by the in-call app). */ public class InCallController extends CallsManagerListenerBase { public class InCallController extends CallsManagerListenerBase implements AppOpsManager.OnOpActiveChangedListener { public static final int IN_CALL_SERVICE_NOTIFICATION_ID = 3; public static final String NOTIFICATION_TAG = InCallController.class.getSimpleName(); Loading Loading @@ -1008,6 +1010,9 @@ public class InCallController extends CallsManagerListenerBase { */ private ArrayList<String> mCallsUsingCamera = new ArrayList<>(); private ArraySet<String> mAllCarrierPrivilegedApps = new ArraySet<>(); private ArraySet<String> mActiveCarrierPrivilegedApps = new ArraySet<>(); public InCallController(Context context, TelecomSystem.SyncRoot lock, CallsManager callsManager, SystemStateHelper systemStateHelper, DefaultDialerCache defaultDialerCache, Timeouts.Adapter timeoutsAdapter, EmergencyCallHelper emergencyCallHelper, Loading Loading @@ -1036,6 +1041,65 @@ public class InCallController extends CallsManagerListenerBase { mToken, packageRestriction, UserHandle.USER_ALL); } @Override public void onOpActiveChanged(@androidx.annotation.NonNull String op, int uid, @androidx.annotation.NonNull String packageName, boolean active) { synchronized (mLock) { if (!mAllCarrierPrivilegedApps.contains(packageName)) { return; } if (active) { mActiveCarrierPrivilegedApps.add(packageName); } else { mActiveCarrierPrivilegedApps.remove(packageName); } maybeTrackMicrophoneUse(isMuted()); } } private void updateAllCarrierPrivilegedUsingMic() { mActiveCarrierPrivilegedApps.clear(); UserManager userManager = mContext.getSystemService(UserManager.class); PackageManager pkgManager = mContext.getPackageManager(); for (String pkg : mAllCarrierPrivilegedApps) { boolean isActive = mActiveCarrierPrivilegedApps.contains(pkg); List<UserHandle> users = userManager.getUserHandles(true); for (UserHandle user : users) { if (isActive) { break; } int uid; try { uid = pkgManager.getPackageUidAsUser(pkg, user.getIdentifier()); } catch (PackageManager.NameNotFoundException e) { continue; } List<AppOpsManager.PackageOps> pkgOps = mAppOpsManager.getOpsForPackage( uid, pkg, OPSTR_RECORD_AUDIO); for (int j = 0; j < pkgOps.size(); j++) { List<AppOpsManager.OpEntry> opEntries = pkgOps.get(j).getOps(); for (int k = 0; k < opEntries.size(); k++) { AppOpsManager.OpEntry entry = opEntries.get(k); if (entry.isRunning()) { mActiveCarrierPrivilegedApps.add(pkg); break; } } } } } } private void updateAllCarrierPrivileged() { mAllCarrierPrivilegedApps.clear(); for (Call call : mCallIdMapper.getCalls()) { mAllCarrierPrivilegedApps.add(call.getConnectionManagerPhoneAccount() .getComponentName().getPackageName()); } } @Override public void onCallAdded(Call call) { if (!isBoundAndConnectedToServices()) { Loading Loading @@ -1116,6 +1180,10 @@ public class InCallController extends CallsManagerListenerBase { } call.removeListener(mCallListener); mCallIdMapper.removeCall(call); if (mCallIdMapper.getCalls().isEmpty()) { mActiveCarrierPrivilegedApps.clear(); mAppOpsManager.stopWatchingActive(this); } maybeTrackMicrophoneUse(isMuted()); onSetCamera(call, null); } Loading Loading @@ -1269,6 +1337,7 @@ public class InCallController extends CallsManagerListenerBase { public void onIsVoipAudioModeChanged(Call call) { Log.d(this, "onIsVoipAudioModeChanged %s", call); updateCall(call); maybeTrackMicrophoneUse(isMuted()); } @Override Loading Loading @@ -1898,10 +1967,18 @@ public class InCallController extends CallsManagerListenerBase { * @param call The call to add. */ private void addCall(Call call) { if (mCallIdMapper.getCalls().size() == 0) { mAppOpsManager.startWatchingActive(new String[] { OPSTR_RECORD_AUDIO }, java.lang.Runnable::run, this); updateAllCarrierPrivileged(); updateAllCarrierPrivilegedUsingMic(); } if (mCallIdMapper.getCallId(call) == null) { mCallIdMapper.addCall(call); call.addListener(mCallListener); } maybeTrackMicrophoneUse(isMuted()); } Loading Loading @@ -2140,7 +2217,8 @@ public class InCallController extends CallsManagerListenerBase { */ private void maybeTrackMicrophoneUse(boolean isMuted) { boolean wasTrackingManagedCall = mIsCallUsingMicrophone; mIsCallUsingMicrophone = isTrackingManagedAliveCall() && !isMuted; mIsCallUsingMicrophone = isTrackingManagedAliveCall() && !isMuted && !carrierPrivilegedUsingMicDuringVoipCall(); if (wasTrackingManagedCall != mIsCallUsingMicrophone) { if (mIsCallUsingMicrophone) { mAppOpsManager.startOp(AppOpsManager.OP_PHONE_CALL_MICROPHONE, myUid(), Loading @@ -2162,6 +2240,11 @@ public class InCallController extends CallsManagerListenerBase { c.getState())); } private boolean carrierPrivilegedUsingMicDuringVoipCall() { return !mActiveCarrierPrivilegedApps.isEmpty() && mCallIdMapper.getCalls().stream().anyMatch(Call::getIsVoipAudioMode); } /** * @return {@code true} if the audio is currently muted, {@code false} otherwise. */ Loading tests/src/com/android/server/telecom/tests/InCallControllerTests.java +1 −1 Original line number Diff line number Diff line Loading @@ -514,7 +514,7 @@ public class InCallControllerTests extends TelecomTestCase { // Pretend that the call has gone away. when(mMockCallsManager.getCalls()).thenReturn(Collections.emptyList()); mInCallController.onCallRemoved(mMockCall); waitForHandlerAction(new Handler(Looper.getMainLooper()), TelecomSystemTest.TEST_TIMEOUT); waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT); verify(mMockPackageManager).revokeRuntimePermission(eq(SYS_PKG), eq(Manifest.permission.ACCESS_FINE_LOCATION), eq(mUserHandle)); Loading Loading
src/com/android/server/telecom/InCallController.java +85 −2 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.server.telecom; import static android.app.AppOpsManager.OPSTR_RECORD_AUDIO; import static android.os.Process.myUid; import android.Manifest; Loading Loading @@ -80,7 +81,8 @@ import java.util.stream.Collectors; * can send updates to the in-call app. This class is created and owned by CallsManager and retains * a binding to the {@link IInCallService} (implemented by the in-call app). */ public class InCallController extends CallsManagerListenerBase { public class InCallController extends CallsManagerListenerBase implements AppOpsManager.OnOpActiveChangedListener { public static final int IN_CALL_SERVICE_NOTIFICATION_ID = 3; public static final String NOTIFICATION_TAG = InCallController.class.getSimpleName(); Loading Loading @@ -1008,6 +1010,9 @@ public class InCallController extends CallsManagerListenerBase { */ private ArrayList<String> mCallsUsingCamera = new ArrayList<>(); private ArraySet<String> mAllCarrierPrivilegedApps = new ArraySet<>(); private ArraySet<String> mActiveCarrierPrivilegedApps = new ArraySet<>(); public InCallController(Context context, TelecomSystem.SyncRoot lock, CallsManager callsManager, SystemStateHelper systemStateHelper, DefaultDialerCache defaultDialerCache, Timeouts.Adapter timeoutsAdapter, EmergencyCallHelper emergencyCallHelper, Loading Loading @@ -1036,6 +1041,65 @@ public class InCallController extends CallsManagerListenerBase { mToken, packageRestriction, UserHandle.USER_ALL); } @Override public void onOpActiveChanged(@androidx.annotation.NonNull String op, int uid, @androidx.annotation.NonNull String packageName, boolean active) { synchronized (mLock) { if (!mAllCarrierPrivilegedApps.contains(packageName)) { return; } if (active) { mActiveCarrierPrivilegedApps.add(packageName); } else { mActiveCarrierPrivilegedApps.remove(packageName); } maybeTrackMicrophoneUse(isMuted()); } } private void updateAllCarrierPrivilegedUsingMic() { mActiveCarrierPrivilegedApps.clear(); UserManager userManager = mContext.getSystemService(UserManager.class); PackageManager pkgManager = mContext.getPackageManager(); for (String pkg : mAllCarrierPrivilegedApps) { boolean isActive = mActiveCarrierPrivilegedApps.contains(pkg); List<UserHandle> users = userManager.getUserHandles(true); for (UserHandle user : users) { if (isActive) { break; } int uid; try { uid = pkgManager.getPackageUidAsUser(pkg, user.getIdentifier()); } catch (PackageManager.NameNotFoundException e) { continue; } List<AppOpsManager.PackageOps> pkgOps = mAppOpsManager.getOpsForPackage( uid, pkg, OPSTR_RECORD_AUDIO); for (int j = 0; j < pkgOps.size(); j++) { List<AppOpsManager.OpEntry> opEntries = pkgOps.get(j).getOps(); for (int k = 0; k < opEntries.size(); k++) { AppOpsManager.OpEntry entry = opEntries.get(k); if (entry.isRunning()) { mActiveCarrierPrivilegedApps.add(pkg); break; } } } } } } private void updateAllCarrierPrivileged() { mAllCarrierPrivilegedApps.clear(); for (Call call : mCallIdMapper.getCalls()) { mAllCarrierPrivilegedApps.add(call.getConnectionManagerPhoneAccount() .getComponentName().getPackageName()); } } @Override public void onCallAdded(Call call) { if (!isBoundAndConnectedToServices()) { Loading Loading @@ -1116,6 +1180,10 @@ public class InCallController extends CallsManagerListenerBase { } call.removeListener(mCallListener); mCallIdMapper.removeCall(call); if (mCallIdMapper.getCalls().isEmpty()) { mActiveCarrierPrivilegedApps.clear(); mAppOpsManager.stopWatchingActive(this); } maybeTrackMicrophoneUse(isMuted()); onSetCamera(call, null); } Loading Loading @@ -1269,6 +1337,7 @@ public class InCallController extends CallsManagerListenerBase { public void onIsVoipAudioModeChanged(Call call) { Log.d(this, "onIsVoipAudioModeChanged %s", call); updateCall(call); maybeTrackMicrophoneUse(isMuted()); } @Override Loading Loading @@ -1898,10 +1967,18 @@ public class InCallController extends CallsManagerListenerBase { * @param call The call to add. */ private void addCall(Call call) { if (mCallIdMapper.getCalls().size() == 0) { mAppOpsManager.startWatchingActive(new String[] { OPSTR_RECORD_AUDIO }, java.lang.Runnable::run, this); updateAllCarrierPrivileged(); updateAllCarrierPrivilegedUsingMic(); } if (mCallIdMapper.getCallId(call) == null) { mCallIdMapper.addCall(call); call.addListener(mCallListener); } maybeTrackMicrophoneUse(isMuted()); } Loading Loading @@ -2140,7 +2217,8 @@ public class InCallController extends CallsManagerListenerBase { */ private void maybeTrackMicrophoneUse(boolean isMuted) { boolean wasTrackingManagedCall = mIsCallUsingMicrophone; mIsCallUsingMicrophone = isTrackingManagedAliveCall() && !isMuted; mIsCallUsingMicrophone = isTrackingManagedAliveCall() && !isMuted && !carrierPrivilegedUsingMicDuringVoipCall(); if (wasTrackingManagedCall != mIsCallUsingMicrophone) { if (mIsCallUsingMicrophone) { mAppOpsManager.startOp(AppOpsManager.OP_PHONE_CALL_MICROPHONE, myUid(), Loading @@ -2162,6 +2240,11 @@ public class InCallController extends CallsManagerListenerBase { c.getState())); } private boolean carrierPrivilegedUsingMicDuringVoipCall() { return !mActiveCarrierPrivilegedApps.isEmpty() && mCallIdMapper.getCalls().stream().anyMatch(Call::getIsVoipAudioMode); } /** * @return {@code true} if the audio is currently muted, {@code false} otherwise. */ Loading
tests/src/com/android/server/telecom/tests/InCallControllerTests.java +1 −1 Original line number Diff line number Diff line Loading @@ -514,7 +514,7 @@ public class InCallControllerTests extends TelecomTestCase { // Pretend that the call has gone away. when(mMockCallsManager.getCalls()).thenReturn(Collections.emptyList()); mInCallController.onCallRemoved(mMockCall); waitForHandlerAction(new Handler(Looper.getMainLooper()), TelecomSystemTest.TEST_TIMEOUT); waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT); verify(mMockPackageManager).revokeRuntimePermission(eq(SYS_PKG), eq(Manifest.permission.ACCESS_FINE_LOCATION), eq(mUserHandle)); Loading