Merge "Dereference cached Bitmaps in EventLogger"
diff --git a/src/com/android/server/telecom/DefaultDialerCache.java b/src/com/android/server/telecom/DefaultDialerCache.java
index 9f7be16..3b36119 100644
--- a/src/com/android/server/telecom/DefaultDialerCache.java
+++ b/src/com/android/server/telecom/DefaultDialerCache.java
@@ -91,6 +91,22 @@
         }
     };
 
+    private final BroadcastReceiver mUserRemovedReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
+                int removedUser = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
+                    UserHandle.USER_NULL);
+                if (removedUser == UserHandle.USER_NULL) {
+                    Log.w(LOG_TAG, "Expected EXTRA_USER_HANDLE with ACTION_USER_REMOVED");
+                } else {
+                    removeUserFromCache(removedUser);
+                    Log.i(LOG_TAG, "Removing user %s", removedUser);
+                }
+            }
+        }
+    };
+
     private final Handler mHandler = new Handler(Looper.getMainLooper());
     private final ContentObserver mDefaultDialerObserver = new ContentObserver(mHandler) {
         @Override
@@ -137,6 +153,8 @@
         IntentFilter bootIntentFilter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
         context.registerReceiverAsUser(mReceiver, UserHandle.ALL, bootIntentFilter, null, null);
 
+        IntentFilter userRemovedFilter = new IntentFilter(Intent.ACTION_USER_REMOVED);
+        context.registerReceiver(mUserRemovedReceiver, userRemovedFilter);
 
         Uri defaultDialerSetting =
                 Settings.Secure.getUriFor(Settings.Secure.DIALER_DEFAULT_APPLICATION);
@@ -221,6 +239,12 @@
         }
     }
 
+    private void removeUserFromCache(int userId) {
+        synchronized (mLock) {
+            mCurrentDefaultDialerPerUser.remove(userId);
+        }
+    }
+
     /**
      * registerContentObserver is really hard to mock out, so here is a getter method for the
      * content observer for testing instead.
diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java
index 40ba21d..72cf998 100644
--- a/src/com/android/server/telecom/TelecomServiceImpl.java
+++ b/src/com/android/server/telecom/TelecomServiceImpl.java
@@ -79,6 +79,7 @@
         }
     }
 
+    private static final String TIME_LINE_ARG = "timeline";
     private static final int DEFAULT_VIDEO_STATE = -1;
 
     private final ITelecomService.Stub mBinderImpl = new ITelecomService.Stub() {
@@ -996,6 +997,10 @@
                                         android.Manifest.permission.MANAGE_OWN_CALLS,
                                         "Self-managed phone accounts must have MANAGE_OWN_CALLS " +
                                                 "permission.");
+
+                                // Self-managed ConnectionServices can ONLY add new incoming calls
+                                // using their own PhoneAccounts.  The checkPackage(..) app opps
+                                // check above ensures this.
                             }
                         }
                         long token = Binder.clearCallingIdentity();
@@ -1086,6 +1091,16 @@
                 if (isSelfManaged) {
                     mContext.enforceCallingOrSelfPermission(Manifest.permission.MANAGE_OWN_CALLS,
                             "Self-managed ConnectionServices require MANAGE_OWN_CALLS permission.");
+
+                    if (!callingPackage.equals(
+                            phoneAccountHandle.getComponentName().getPackageName())
+                            && !canCallPhone(callingPackage,
+                            "CALL_PHONE permission required to place calls.")) {
+                        // The caller is not allowed to place calls, so we want to ensure that it
+                        // can only place calls through itself.
+                        throw new SecurityException("Self-managed ConnectionServices can only "
+                                + "place calls through their own ConnectionService.");
+                    }
                 } else if (!canCallPhone(callingPackage, "placeCall")) {
                     throw new SecurityException("Package " + callingPackage
                             + " is not allowed to place phone calls");
@@ -1210,6 +1225,7 @@
                 Analytics.dumpToEncodedProto(writer, args);
                 return;
             }
+            boolean isTimeLineView = (args.length > 0 && TIME_LINE_ARG.equalsIgnoreCase(args[0]));
 
             final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
             if (mCallsManager != null) {
@@ -1228,8 +1244,11 @@
                 Analytics.dump(pw);
                 pw.decreaseIndent();
             }
-
-            Log.dumpEvents(pw);
+            if (isTimeLineView) {
+                Log.dumpEventsTimeline(pw);
+            } else {
+                Log.dumpEvents(pw);
+            }
         }
 
         /**
diff --git a/tests/src/com/android/server/telecom/tests/DefaultDialerCacheTest.java b/tests/src/com/android/server/telecom/tests/DefaultDialerCacheTest.java
index e73df61..82fee3e 100644
--- a/tests/src/com/android/server/telecom/tests/DefaultDialerCacheTest.java
+++ b/tests/src/com/android/server/telecom/tests/DefaultDialerCacheTest.java
@@ -51,6 +51,7 @@
     private DefaultDialerCache mDefaultDialerCache;
     private ContentObserver mDefaultDialerSettingObserver;
     private BroadcastReceiver mPackageChangeReceiver;
+    private BroadcastReceiver mUserRemovedReceiver;
 
     @Mock private DefaultDialerCache.DefaultDialerManagerAdapter mMockDefaultDialerManager;
 
@@ -58,17 +59,24 @@
         super.setUp();
         mContext = mComponentContextFixture.getTestDouble().getApplicationContext();
 
-        ArgumentCaptor<BroadcastReceiver> receiverCaptor =
+        ArgumentCaptor<BroadcastReceiver> packageReceiverCaptor =
                 ArgumentCaptor.forClass(BroadcastReceiver.class);
 
         mDefaultDialerCache = new DefaultDialerCache(
                 mContext, mMockDefaultDialerManager, new TelecomSystem.SyncRoot() { });
 
         verify(mContext, times(2)).registerReceiverAsUser(
-                receiverCaptor.capture(), eq(UserHandle.ALL), any(IntentFilter.class),
+            packageReceiverCaptor.capture(), eq(UserHandle.ALL), any(IntentFilter.class),
                 isNull(String.class), isNull(Handler.class));
         // Receive the first receiver that was captured, the package change receiver.
-        mPackageChangeReceiver = receiverCaptor.getAllValues().get(0);
+        mPackageChangeReceiver = packageReceiverCaptor.getAllValues().get(0);
+
+        ArgumentCaptor<BroadcastReceiver> userRemovedReceiverCaptor =
+            ArgumentCaptor.forClass(BroadcastReceiver.class);
+        verify(mContext).registerReceiver(
+            userRemovedReceiverCaptor.capture(), any(IntentFilter.class));
+        mUserRemovedReceiver = userRemovedReceiverCaptor.getAllValues().get(0);
+
         mDefaultDialerSettingObserver = mDefaultDialerCache.getContentObserver();
 
         when(mMockDefaultDialerManager.getDefaultDialerApplication(any(Context.class), eq(USER0)))
@@ -138,6 +146,24 @@
     }
 
     @SmallTest
+    public void testUserRemoved() {
+        assertEquals(mDefaultDialerCache.getDefaultDialerApplication(USER0), DIALER1);
+        assertEquals(mDefaultDialerCache.getDefaultDialerApplication(USER1), DIALER2);
+
+        Intent userRemovalIntent = new Intent(Intent.ACTION_USER_REMOVED);
+        userRemovalIntent.putExtra(Intent.EXTRA_USER_HANDLE, USER0);
+        mUserRemovedReceiver.onReceive(mContext, userRemovalIntent);
+
+        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));
+    }
+
+    @SmallTest
     public void testPackageRemovedWithoutReplace() {
         assertEquals(mDefaultDialerCache.getDefaultDialerApplication(USER0), DIALER1);
         assertEquals(mDefaultDialerCache.getDefaultDialerApplication(USER1), DIALER2);