Merge "Revoke the location permission properly after the emergency calls" into main am: 7fa700d337 am: ba3f884cc2

Original change: https://android-review.googlesource.com/c/platform/packages/services/Telecomm/+/3116896

Change-Id: I3244c8128616124c2d9ee570e3e2789943748702
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/flags/telecom_call_flags.aconfig b/flags/telecom_call_flags.aconfig
index 2fde55a..fa6f68e 100644
--- a/flags/telecom_call_flags.aconfig
+++ b/flags/telecom_call_flags.aconfig
@@ -3,6 +3,13 @@
 
 # OWNER=tjstuart TARGET=24Q3
 flag {
+  name: "prevent_redundant_location_permission_grant_and_revoke"
+  namespace: "telecom"
+  description: "avoid redundant action of grant and revoke location permission for multiple emergency calls"
+  bug: "345386002"
+}
+
+flag {
   name: "transactional_cs_verifier"
   namespace: "telecom"
   description: "verify connection service callbacks via a transaction"
diff --git a/src/com/android/server/telecom/EmergencyCallHelper.java b/src/com/android/server/telecom/EmergencyCallHelper.java
index 5ab0e99..c0e38ca 100644
--- a/src/com/android/server/telecom/EmergencyCallHelper.java
+++ b/src/com/android/server/telecom/EmergencyCallHelper.java
@@ -24,6 +24,7 @@
 import android.telecom.PhoneAccountHandle;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.telecom.flags.FeatureFlags;
 
 /**
  * Helps with emergency calls by:
@@ -51,19 +52,25 @@
     private long mLastEmergencyCallTimestampMillis;
     private long mLastOutgoingEmergencyCallTimestampMillis;
 
+    private final FeatureFlags mFeatureFlags;
+
     @VisibleForTesting
     public EmergencyCallHelper(
             Context context,
             DefaultDialerCache defaultDialerCache,
-            Timeouts.Adapter timeoutsAdapter) {
+            Timeouts.Adapter timeoutsAdapter,
+            FeatureFlags featureFlags) {
         mContext = context;
         mDefaultDialerCache = defaultDialerCache;
         mTimeoutsAdapter = timeoutsAdapter;
+        mFeatureFlags = featureFlags;
     }
 
     @VisibleForTesting
     public void maybeGrantTemporaryLocationPermission(Call call, UserHandle userHandle) {
-        if (shouldGrantTemporaryLocationPermission(call)) {
+        if (shouldGrantTemporaryLocationPermission(call) && (
+                !mFeatureFlags.preventRedundantLocationPermissionGrantAndRevoke()
+                || !wasGrantedTemporaryLocationPermission())) {
             grantLocationPermission(userHandle);
         }
         if (call != null && call.isEmergencyCall()) {
diff --git a/src/com/android/server/telecom/InCallController.java b/src/com/android/server/telecom/InCallController.java
index 0f62f87..5a6f0ea 100644
--- a/src/com/android/server/telecom/InCallController.java
+++ b/src/com/android/server/telecom/InCallController.java
@@ -1301,6 +1301,8 @@
     private ArraySet<String> mAllCarrierPrivilegedApps = new ArraySet<>();
     private ArraySet<String> mActiveCarrierPrivilegedApps = new ArraySet<>();
 
+    private java.lang.Runnable mCallRemovedRunnable;
+
     public InCallController(Context context, TelecomSystem.SyncRoot lock, CallsManager callsManager,
             SystemStateHelper systemStateHelper, DefaultDialerCache defaultDialerCache,
             Timeouts.Adapter timeoutsAdapter, EmergencyCallHelper emergencyCallHelper,
@@ -1516,7 +1518,11 @@
             /** Let's add a 2 second delay before we send unbind to the services to hopefully
              *  give them enough time to process all the pending messages.
              */
-            mHandler.postDelayed(new Runnable("ICC.oCR", mLock) {
+            if (mCallRemovedRunnable != null
+                    && mFeatureFlags.preventRedundantLocationPermissionGrantAndRevoke()) {
+                mHandler.removeCallbacks(mCallRemovedRunnable);
+            }
+            mCallRemovedRunnable = new Runnable("ICC.oCR", mLock) {
                 @Override
                 public void loggedRun() {
                     // Check again to make sure there are no active calls for the associated user.
@@ -1530,8 +1536,10 @@
                         mEmergencyCallHelper.maybeRevokeTemporaryLocationPermission();
                     }
                 }
-            }.prepare(), mTimeoutsAdapter.getCallRemoveUnbindInCallServicesDelay(
-                    mContext.getContentResolver()));
+            }.prepare();
+            mHandler.postDelayed(mCallRemovedRunnable,
+                    mTimeoutsAdapter.getCallRemoveUnbindInCallServicesDelay(
+                            mContext.getContentResolver()));
         }
         call.removeListener(mCallListener);
         mCallIdMapper.removeCall(call);
diff --git a/src/com/android/server/telecom/TelecomSystem.java b/src/com/android/server/telecom/TelecomSystem.java
index 7ff083f..1cbe846 100644
--- a/src/com/android/server/telecom/TelecomSystem.java
+++ b/src/com/android/server/telecom/TelecomSystem.java
@@ -285,7 +285,7 @@
                             mContactsAsyncHelper, mLock);
 
             EmergencyCallHelper emergencyCallHelper = new EmergencyCallHelper(mContext,
-                    defaultDialerCache, timeoutsAdapter);
+                    defaultDialerCache, timeoutsAdapter, mFeatureFlags);
 
             InCallControllerFactory inCallControllerFactory = new InCallControllerFactory() {
                 @Override
diff --git a/tests/src/com/android/server/telecom/tests/EmergencyCallHelperTest.java b/tests/src/com/android/server/telecom/tests/EmergencyCallHelperTest.java
index f2ad2f7..cc1c38a 100644
--- a/tests/src/com/android/server/telecom/tests/EmergencyCallHelperTest.java
+++ b/tests/src/com/android/server/telecom/tests/EmergencyCallHelperTest.java
@@ -75,7 +75,7 @@
     mContext = mComponentContextFixture.getTestDouble().getApplicationContext();
     when(mContext.getPackageManager()).thenReturn(mPackageManager);
     mEmergencyCallHelper = new EmergencyCallHelper(mContext, mDefaultDialerCache,
-        mTimeoutsAdapter);
+        mTimeoutsAdapter, mFeatureFlags);
     when(mDefaultDialerCache.getSystemDialerApplication()).thenReturn(SYSTEM_DIALER_PACKAGE);
 
     //start with no perms
@@ -185,6 +185,61 @@
 
   @SmallTest
   @Test
+  public void testPermGrantAndRevokeForEmergencyCall() {
+
+    when(mFeatureFlags.preventRedundantLocationPermissionGrantAndRevoke()).thenReturn(true);
+
+    mEmergencyCallHelper.maybeGrantTemporaryLocationPermission(mCall, mUserHandle);
+    mEmergencyCallHelper.maybeRevokeTemporaryLocationPermission();
+
+    //permissions should be granted then revoked
+    verifyGrantInvokedFor(ACCESS_BACKGROUND_LOCATION);
+    verifyGrantInvokedFor(ACCESS_FINE_LOCATION);
+    verifyRevokeInvokedFor(ACCESS_BACKGROUND_LOCATION);
+    verifyRevokeInvokedFor(ACCESS_FINE_LOCATION);
+  }
+
+  @SmallTest
+  @Test
+  public void testPermGrantAndRevokeForMultiEmergencyCall() {
+
+    when(mFeatureFlags.preventRedundantLocationPermissionGrantAndRevoke()).thenReturn(true);
+
+    //first call is emergency call
+    mEmergencyCallHelper.maybeGrantTemporaryLocationPermission(mCall, mUserHandle);
+    //second call is emergency call
+    mEmergencyCallHelper.maybeGrantTemporaryLocationPermission(mCall, mUserHandle);
+    mEmergencyCallHelper.maybeRevokeTemporaryLocationPermission();
+
+    //permissions should be granted then revoked
+    verifyGrantInvokedFor(ACCESS_BACKGROUND_LOCATION);
+    verifyGrantInvokedFor(ACCESS_FINE_LOCATION);
+    verifyRevokeInvokedFor(ACCESS_BACKGROUND_LOCATION);
+    verifyRevokeInvokedFor(ACCESS_FINE_LOCATION);
+  }
+
+  @SmallTest
+  @Test
+  public void testPermGrantAndRevokeForEmergencyCallAndNormalCall() {
+
+    when(mFeatureFlags.preventRedundantLocationPermissionGrantAndRevoke()).thenReturn(true);
+
+    //first call is emergency call
+    mEmergencyCallHelper.maybeGrantTemporaryLocationPermission(mCall, mUserHandle);
+    //second call is normal call
+    when(mCall.isEmergencyCall()).thenReturn(false);
+    mEmergencyCallHelper.maybeGrantTemporaryLocationPermission(mCall, mUserHandle);
+    mEmergencyCallHelper.maybeRevokeTemporaryLocationPermission();
+
+    //permissions should be granted then revoked
+    verifyGrantInvokedFor(ACCESS_BACKGROUND_LOCATION);
+    verifyGrantInvokedFor(ACCESS_FINE_LOCATION);
+    verifyRevokeInvokedFor(ACCESS_BACKGROUND_LOCATION);
+    verifyRevokeInvokedFor(ACCESS_FINE_LOCATION);
+  }
+
+  @SmallTest
+  @Test
   public void testNoPermGrantForNonEmergencyCall() {
 
     when(mCall.isEmergencyCall()).thenReturn(false);
diff --git a/tests/src/com/android/server/telecom/tests/InCallControllerTests.java b/tests/src/com/android/server/telecom/tests/InCallControllerTests.java
index 449aa41..bea3fe3 100644
--- a/tests/src/com/android/server/telecom/tests/InCallControllerTests.java
+++ b/tests/src/com/android/server/telecom/tests/InCallControllerTests.java
@@ -230,7 +230,7 @@
                 new ComponentName(SYS_PKG, SYS_CLASS));
         when(mDefaultDialerCache.getBTInCallServicePackages()).thenReturn(new String[] {BT_PKG});
         mEmergencyCallHelper = new EmergencyCallHelper(mMockContext, mDefaultDialerCache,
-                mTimeoutsAdapter);
+                mTimeoutsAdapter, mFeatureFlags);
         when(mMockCallsManager.getRoleManagerAdapter()).thenReturn(mMockRoleManagerAdapter);
         when(mMockContext.getSystemService(eq(Context.NOTIFICATION_SERVICE)))
                 .thenReturn(mNotificationManager);