Telecom fixes related to RoleManager

- fix setState method so you can't transition from ANSWERED to ACTIVE
state.  I found a case when running some of the CTS where this was
flaking because the CTS test runs quickly enough that it was possible for
some of the Telecom answer call code to try setting a call to answered
when the underlying CS has already set it active.  ANSWERED is the
intermediate state before it becomes active.
- factor access to RoleManager for getting dialer role into the
RoleManagerAdapter.
- add ability to set an override default dialer via command line for CTS
test purposes since the RoleManager is too trigger happy when switching
the default dialer.
- change DefaultDialerCache to always refresh default dialer cache when
queried; this is an interim step until we can get the RoleManager to tell
us when the role filler for Dialer is changed.

Test: Run the CTS tests over, and over, and over, and over....
Bug: 131065482
AOSP: infeasible for now; will refactor-cherry-pick into aosp but it'll be
messy.
Change-Id: Id42b6157c338dc0a96a7db0372a5bc2df3f4d2c7
(cherry picked from commit bb4b46ee8a2799b80e419f3660702ca8555e41a5)
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index ff67d32..c8eee36 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -38,6 +38,7 @@
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
     <uses-permission android:name="android.permission.MANAGE_USERS" />
+    <uses-permission android:name="android.permission.MANAGE_ROLE_HOLDERS" />
     <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
     <!-- Required to determine source of ongoing audio recordings. -->
     <uses-permission android:name="android.permission.MODIFY_AUDIO_ROUTING" />
diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java
index ea09af4..fc90acb 100644
--- a/src/com/android/server/telecom/Call.java
+++ b/src/com/android/server/telecom/Call.java
@@ -891,12 +891,17 @@
      */
     public boolean setState(int newState, String tag) {
         if (mState != newState) {
-            Log.v(this, "setState %s -> %s", mState, newState);
+            Log.v(this, "setState %s -> %s", CallState.toString(mState),
+                    CallState.toString(newState));
 
             if (newState == CallState.DISCONNECTED && shouldContinueProcessingAfterDisconnect()) {
                 Log.w(this, "continuing processing disconnected call with another service");
                 mCreateConnectionProcessor.continueProcessingIfPossible(this, mDisconnectCause);
                 return false;
+            } else if (newState == CallState.ANSWERED && mState == CallState.ACTIVE) {
+                Log.w(this, "setState %s -> %s; call already active.", CallState.toString(mState),
+                        CallState.toString(newState));
+                return false;
             }
 
             updateVideoHistoryViaState(mState, newState);
diff --git a/src/com/android/server/telecom/DefaultDialerCache.java b/src/com/android/server/telecom/DefaultDialerCache.java
index 749cb40..9d24794 100644
--- a/src/com/android/server/telecom/DefaultDialerCache.java
+++ b/src/com/android/server/telecom/DefaultDialerCache.java
@@ -133,13 +133,16 @@
     private final DefaultDialerManagerAdapter mDefaultDialerManagerAdapter;
     private final TelecomSystem.SyncRoot mLock;
     private final String mSystemDialerName;
+    private final RoleManagerAdapter mRoleManagerAdapter;
     private SparseArray<String> mCurrentDefaultDialerPerUser = new SparseArray<>();
 
     public DefaultDialerCache(Context context,
             DefaultDialerManagerAdapter defaultDialerManagerAdapter,
+            RoleManagerAdapter roleManagerAdapter,
             TelecomSystem.SyncRoot lock) {
         mContext = context;
         mDefaultDialerManagerAdapter = defaultDialerManagerAdapter;
+        mRoleManagerAdapter = roleManagerAdapter;
         mLock = lock;
         mSystemDialerName = TelecomServiceImpl.getSystemDialerPackage(mContext);
 
@@ -173,12 +176,15 @@
             return null;
         }
 
-        synchronized (mLock) {
-            String defaultDialer = mCurrentDefaultDialerPerUser.get(userId);
-            if (defaultDialer != null) {
-                return defaultDialer;
-            }
-        }
+        // TODO: Re-enable this when we are able to use the cache once more.  RoleManager does not
+        // provide a means for being informed when the role holder changes at the current time.
+        //
+        //synchronized (mLock) {
+        //    String defaultDialer = mCurrentDefaultDialerPerUser.get(userId);
+        //    if (defaultDialer != null) {
+        //        return defaultDialer;
+        //    }
+        //}
         return refreshCacheForUser(userId);
     }
 
@@ -206,7 +212,7 @@
 
     private String refreshCacheForUser(int userId) {
         String currentDefaultDialer =
-                mDefaultDialerManagerAdapter.getDefaultDialerApplication(mContext, userId);
+                mRoleManagerAdapter.getDefaultDialerApp(userId);
         synchronized (mLock) {
             mCurrentDefaultDialerPerUser.put(userId, currentDefaultDialer);
         }
diff --git a/src/com/android/server/telecom/RoleManagerAdapter.java b/src/com/android/server/telecom/RoleManagerAdapter.java
index f1eb455..6e9f01d 100644
--- a/src/com/android/server/telecom/RoleManagerAdapter.java
+++ b/src/com/android/server/telecom/RoleManagerAdapter.java
@@ -65,6 +65,21 @@
     void setTestDefaultCallScreeningApp(String packageName);
 
     /**
+     * Returns the package name of the app which fills the {@link android.app.role.RoleManager}
+     * {@link android.app.role.RoleManager#ROLE_DIALER} role.
+     * @return the package name of the app filling the role, {@code null} otherwise}.
+     */
+    String getDefaultDialerApp(int user);
+
+    /**
+     * Override the {@link android.app.role.RoleManager} default dialer app with another value.
+     * Used for testing purposes only.
+     * @param packageName Package name of the app to fill the default dialer role.  Where
+     *                    {@code null}, the override is removed.
+     */
+    void setTestDefaultDialer(String packageName);
+
+    /**
      * @return List of package names of companion apps, or empty list if there are none.
      */
     List<String> getCallCompanionApps();
diff --git a/src/com/android/server/telecom/RoleManagerAdapterImpl.java b/src/com/android/server/telecom/RoleManagerAdapterImpl.java
index 5fb8451..4fe7fb0 100644
--- a/src/com/android/server/telecom/RoleManagerAdapterImpl.java
+++ b/src/com/android/server/telecom/RoleManagerAdapterImpl.java
@@ -32,10 +32,12 @@
 public class RoleManagerAdapterImpl implements RoleManagerAdapter {
     private static final String ROLE_CALL_REDIRECTION_APP = RoleManager.ROLE_CALL_REDIRECTION;
     private static final String ROLE_CALL_SCREENING = RoleManager.ROLE_CALL_SCREENING;
+    private static final String ROLE_DIALER = RoleManager.ROLE_DIALER;
 
     private String mOverrideDefaultCallRedirectionApp = null;
     private String mOverrideDefaultCallScreeningApp = null;
     private String mOverrideDefaultCarModeApp = null;
+    private String mOverrideDefaultDialerApp = null;
     private List<String> mOverrideCallCompanionApps = new ArrayList<>();
     private Context mContext;
     private RoleManager mRoleManager;
@@ -73,6 +75,19 @@
     }
 
     @Override
+    public String getDefaultDialerApp(int user) {
+        if (mOverrideDefaultDialerApp != null) {
+            return mOverrideDefaultDialerApp;
+        }
+        return getRoleManagerDefaultDialerApp(user);
+    }
+
+    @Override
+    public void setTestDefaultDialer(String packageName) {
+        mOverrideDefaultDialerApp = packageName;
+    }
+
+    @Override
     public List<String> getCallCompanionApps() {
         List<String> callCompanionApps = new ArrayList<>();
         callCompanionApps.addAll(mOverrideCallCompanionApps);
@@ -115,6 +130,15 @@
         return roleHolders.get(0);
     }
 
+    private String getRoleManagerDefaultDialerApp(int user) {
+        List<String> roleHolders = mRoleManager.getRoleHoldersAsUser(ROLE_DIALER,
+                new UserHandle(user));
+        if (roleHolders == null || roleHolders.isEmpty()) {
+            return null;
+        }
+        return roleHolders.get(0);
+    }
+
     // TODO in R: query and return car mode apps
     private String getRoleManagerCarModeDialerApp() {
         return null;
diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java
index 4e8df7a..107ca75 100644
--- a/src/com/android/server/telecom/TelecomServiceImpl.java
+++ b/src/com/android/server/telecom/TelecomServiceImpl.java
@@ -1633,6 +1633,28 @@
                 Log.endSession();
             }
         }
+
+        @Override
+        public void setTestDefaultDialer(String packageName) {
+            try {
+                Log.startSession("TSI.sTDD");
+                enforceModifyPermission();
+                if (Binder.getCallingUid() != Process.SHELL_UID
+                        && Binder.getCallingUid() != Process.ROOT_UID) {
+                    throw new SecurityException("Shell-only API.");
+                }
+                synchronized (mLock) {
+                    long token = Binder.clearCallingIdentity();
+                    try {
+                        mCallsManager.getRoleManagerAdapter().setTestDefaultDialer(packageName);
+                    } finally {
+                        Binder.restoreCallingIdentity(token);
+                    }
+                }
+            } finally {
+                Log.endSession();
+            }
+        }
     };
 
     /**
@@ -1976,8 +1998,17 @@
 
     private boolean isPrivilegedDialerCalling(String callingPackage) {
         mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage);
-        return mDefaultDialerCache.isDefaultOrSystemDialer(
-                callingPackage, Binder.getCallingUserHandle().getIdentifier());
+
+        // Note: Important to clear the calling identity since the code below calls into RoleManager
+        // to check who holds the dialer role, and that requires MANAGE_ROLE_HOLDERS permission
+        // which is a system permission.
+        long token = Binder.clearCallingIdentity();
+        try {
+            return mDefaultDialerCache.isDefaultOrSystemDialer(
+                    callingPackage, Binder.getCallingUserHandle().getIdentifier());
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
     }
 
     private TelephonyManager getTelephonyManager() {
diff --git a/src/com/android/server/telecom/TelecomSystem.java b/src/com/android/server/telecom/TelecomSystem.java
index 9606ea3..733447f 100644
--- a/src/com/android/server/telecom/TelecomSystem.java
+++ b/src/com/android/server/telecom/TelecomSystem.java
@@ -209,7 +209,7 @@
                 new DefaultDialerCache.DefaultDialerManagerAdapterImpl();
 
         DefaultDialerCache defaultDialerCache = new DefaultDialerCache(mContext,
-                defaultDialerAdapter, mLock);
+                defaultDialerAdapter, roleManagerAdapter, mLock);
 
         Log.startSession("TS.init");
         mPhoneAccountRegistrar = new PhoneAccountRegistrar(mContext, defaultDialerCache,
diff --git a/tests/src/com/android/server/telecom/tests/DefaultDialerCacheTest.java b/tests/src/com/android/server/telecom/tests/DefaultDialerCacheTest.java
index 94e6631..e8bca03 100644
--- a/tests/src/com/android/server/telecom/tests/DefaultDialerCacheTest.java
+++ b/tests/src/com/android/server/telecom/tests/DefaultDialerCacheTest.java
@@ -27,6 +27,7 @@
 import android.test.suitebuilder.annotation.SmallTest;
 
 import com.android.server.telecom.DefaultDialerCache;
+import com.android.server.telecom.RoleManagerAdapter;
 import com.android.server.telecom.TelecomSystem;
 
 import org.junit.Before;
@@ -60,6 +61,7 @@
     private BroadcastReceiver mUserRemovedReceiver;
 
     @Mock private DefaultDialerCache.DefaultDialerManagerAdapter mMockDefaultDialerManager;
+    @Mock private RoleManagerAdapter mRoleManagerAdapter;
 
     @Override
     @Before
@@ -71,7 +73,8 @@
                 ArgumentCaptor.forClass(BroadcastReceiver.class);
 
         mDefaultDialerCache = new DefaultDialerCache(
-                mContext, mMockDefaultDialerManager, new TelecomSystem.SyncRoot() { });
+                mContext, mMockDefaultDialerManager, mRoleManagerAdapter,
+                new TelecomSystem.SyncRoot() { });
 
         verify(mContext, times(2)).registerReceiverAsUser(
             packageReceiverCaptor.capture(), eq(UserHandle.ALL), any(IntentFilter.class),
@@ -93,6 +96,9 @@
                 .thenReturn(DIALER2);
         when(mMockDefaultDialerManager.getDefaultDialerApplication(any(Context.class), eq(USER2)))
                 .thenReturn(DIALER3);
+        when(mRoleManagerAdapter.getDefaultDialerApp(eq(USER0))).thenReturn(DIALER1);
+        when(mRoleManagerAdapter.getDefaultDialerApp(eq(USER1))).thenReturn(DIALER2);
+        when(mRoleManagerAdapter.getDefaultDialerApp(eq(USER2))).thenReturn(DIALER3);
     }
 
     @SmallTest
@@ -107,12 +113,12 @@
         assertEquals(mDefaultDialerCache.getDefaultDialerApplication(USER1), DIALER2);
         assertEquals(mDefaultDialerCache.getDefaultDialerApplication(USER2), DIALER3);
 
-        verify(mMockDefaultDialerManager, times(1))
-                .getDefaultDialerApplication(any(Context.class), eq(USER0));
-        verify(mMockDefaultDialerManager, times(1))
-                .getDefaultDialerApplication(any(Context.class), eq(USER1));
-        verify(mMockDefaultDialerManager, times(1))
-                .getDefaultDialerApplication(any(Context.class), eq(USER2));
+        verify(mRoleManagerAdapter, times(4))
+                .getDefaultDialerApp(eq(USER0));
+        verify(mRoleManagerAdapter, times(2))
+                .getDefaultDialerApp(eq(USER1));
+        verify(mRoleManagerAdapter, times(2))
+                .getDefaultDialerApp(eq(USER2));
     }
 
     @SmallTest
@@ -125,15 +131,11 @@
 
         Intent packageChangeIntent = new Intent(Intent.ACTION_PACKAGE_CHANGED,
                 Uri.fromParts("package", DIALER1, null));
-        when(mMockDefaultDialerManager.getDefaultDialerApplication(any(Context.class), eq(USER0)))
-                .thenReturn(DIALER2);
+        when(mRoleManagerAdapter.getDefaultDialerApp(eq(USER0))).thenReturn(DIALER2);
         mPackageChangeReceiver.onReceive(mContext, packageChangeIntent);
-        verify(mMockDefaultDialerManager, times(2))
-                .getDefaultDialerApplication(any(Context.class), eq(USER0));
-        verify(mMockDefaultDialerManager, times(2))
-                .getDefaultDialerApplication(any(Context.class), eq(USER1));
-        verify(mMockDefaultDialerManager, times(2))
-                .getDefaultDialerApplication(any(Context.class), eq(USER2));
+        verify(mRoleManagerAdapter, times(2)).getDefaultDialerApp(eq(USER0));
+        verify(mRoleManagerAdapter, times(2)).getDefaultDialerApp(eq(USER1));
+        verify(mRoleManagerAdapter, times(2)).getDefaultDialerApp(eq(USER2));
 
         assertEquals(mDefaultDialerCache.getDefaultDialerApplication(USER0), DIALER2);
     }
@@ -148,12 +150,9 @@
         Intent packageChangeIntent = new Intent(Intent.ACTION_PACKAGE_CHANGED,
                 Uri.fromParts("package", "red.orange.blue", null));
         mPackageChangeReceiver.onReceive(mContext, packageChangeIntent);
-        verify(mMockDefaultDialerManager, times(2))
-                .getDefaultDialerApplication(any(Context.class), eq(USER0));
-        verify(mMockDefaultDialerManager, times(2))
-                .getDefaultDialerApplication(any(Context.class), eq(USER1));
-        verify(mMockDefaultDialerManager, times(2))
-                .getDefaultDialerApplication(any(Context.class), eq(USER2));
+        verify(mRoleManagerAdapter, times(2)).getDefaultDialerApp(eq(USER0));
+        verify(mRoleManagerAdapter, times(2)).getDefaultDialerApp(eq(USER1));
+        verify(mRoleManagerAdapter, times(2)).getDefaultDialerApp(eq(USER2));
     }
 
     @SmallTest
@@ -169,10 +168,8 @@
         assertEquals(mDefaultDialerCache.getDefaultDialerApplication(USER0), DIALER1);
         assertEquals(mDefaultDialerCache.getDefaultDialerApplication(USER1), DIALER2);
 
-        verify(mMockDefaultDialerManager, times(2))
-                .getDefaultDialerApplication(any(Context.class), eq(USER0));
-        verify(mMockDefaultDialerManager, times(1))
-                .getDefaultDialerApplication(any(Context.class), eq(USER1));
+        verify(mRoleManagerAdapter, times(2)).getDefaultDialerApp(eq(USER0));
+        verify(mRoleManagerAdapter, times(2)).getDefaultDialerApp(eq(USER1));
     }
 
     @SmallTest
@@ -187,12 +184,9 @@
         packageChangeIntent.putExtra(Intent.EXTRA_REPLACING, false);
 
         mPackageChangeReceiver.onReceive(mContext, packageChangeIntent);
-        verify(mMockDefaultDialerManager, times(2))
-                .getDefaultDialerApplication(any(Context.class), eq(USER0));
-        verify(mMockDefaultDialerManager, times(1))
-                .getDefaultDialerApplication(any(Context.class), eq(USER1));
-        verify(mMockDefaultDialerManager, times(1))
-                .getDefaultDialerApplication(any(Context.class), eq(USER2));
+        verify(mRoleManagerAdapter, times(2)).getDefaultDialerApp(eq(USER0));
+        verify(mRoleManagerAdapter, times(1)).getDefaultDialerApp(eq(USER1));
+        verify(mRoleManagerAdapter, times(1)).getDefaultDialerApp(eq(USER2));
     }
 
     @SmallTest
@@ -206,12 +200,9 @@
                 Uri.fromParts("package", "ppp.qqq.zzz", null));
 
         mPackageChangeReceiver.onReceive(mContext, packageChangeIntent);
-        verify(mMockDefaultDialerManager, times(2))
-                .getDefaultDialerApplication(any(Context.class), eq(USER0));
-        verify(mMockDefaultDialerManager, times(2))
-                .getDefaultDialerApplication(any(Context.class), eq(USER1));
-        verify(mMockDefaultDialerManager, times(2))
-                .getDefaultDialerApplication(any(Context.class), eq(USER2));
+        verify(mRoleManagerAdapter, times(2)).getDefaultDialerApp(eq(USER0));
+        verify(mRoleManagerAdapter, times(2)).getDefaultDialerApp(eq(USER1));
+        verify(mRoleManagerAdapter, times(2)).getDefaultDialerApp(eq(USER2));
     }
 
     @SmallTest
@@ -226,12 +217,9 @@
         packageChangeIntent.putExtra(Intent.EXTRA_REPLACING, true);
 
         mPackageChangeReceiver.onReceive(mContext, packageChangeIntent);
-        verify(mMockDefaultDialerManager, times(1))
-                .getDefaultDialerApplication(any(Context.class), eq(USER0));
-        verify(mMockDefaultDialerManager, times(1))
-                .getDefaultDialerApplication(any(Context.class), eq(USER1));
-        verify(mMockDefaultDialerManager, times(1))
-                .getDefaultDialerApplication(any(Context.class), eq(USER2));
+        verify(mRoleManagerAdapter, times(1)).getDefaultDialerApp(eq(USER0));
+        verify(mRoleManagerAdapter, times(1)).getDefaultDialerApp(eq(USER1));
+        verify(mRoleManagerAdapter, times(1)).getDefaultDialerApp(eq(USER2));
     }
 
     @SmallTest
@@ -241,20 +229,14 @@
         assertEquals(mDefaultDialerCache.getDefaultDialerApplication(USER1), DIALER2);
         assertEquals(mDefaultDialerCache.getDefaultDialerApplication(USER2), DIALER3);
 
-        when(mMockDefaultDialerManager.getDefaultDialerApplication(any(Context.class), eq(USER0)))
-                .thenReturn(DIALER2);
-        when(mMockDefaultDialerManager.getDefaultDialerApplication(any(Context.class), eq(USER1)))
-                .thenReturn(DIALER2);
-        when(mMockDefaultDialerManager.getDefaultDialerApplication(any(Context.class), eq(USER2)))
-                .thenReturn(DIALER2);
+        when(mRoleManagerAdapter.getDefaultDialerApp(eq(USER0))).thenReturn(DIALER2);
+        when(mRoleManagerAdapter.getDefaultDialerApp(eq(USER1))).thenReturn(DIALER2);
+        when(mRoleManagerAdapter.getDefaultDialerApp(eq(USER2))).thenReturn(DIALER2);
         mDefaultDialerSettingObserver.onChange(false);
 
-        verify(mMockDefaultDialerManager, times(2))
-                .getDefaultDialerApplication(any(Context.class), eq(USER0));
-        verify(mMockDefaultDialerManager, times(2))
-                .getDefaultDialerApplication(any(Context.class), eq(USER2));
-        verify(mMockDefaultDialerManager, times(2))
-                .getDefaultDialerApplication(any(Context.class), eq(USER2));
+        verify(mRoleManagerAdapter, times(2)).getDefaultDialerApp(eq(USER0));
+        verify(mRoleManagerAdapter, times(2)).getDefaultDialerApp(eq(USER2));
+        verify(mRoleManagerAdapter, times(2)).getDefaultDialerApp(eq(USER2));
 
         assertEquals(mDefaultDialerCache.getDefaultDialerApplication(USER0), DIALER2);
         assertEquals(mDefaultDialerCache.getDefaultDialerApplication(USER1), DIALER2);