Wiring videoState through from telephony.

- Adding call video state history tracking, which is used to ensure
we log whether video was active at any point to the call log.
- Adding logging of video state to call log.


Bug: 16285417
Bug: 16013178
Change-Id: I3b47c88b13dc73941ca80463fc0c6ae7cdd86749
diff --git a/src/com/android/telecomm/Call.java b/src/com/android/telecomm/Call.java
index b06b043..27a995a 100644
--- a/src/com/android/telecomm/Call.java
+++ b/src/com/android/telecomm/Call.java
@@ -16,14 +16,11 @@
 
 package com.android.telecomm;
 
-import android.content.ComponentName;
-import android.content.ContentUris;
 import android.graphics.Bitmap;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
-import android.provider.ContactsContract.Contacts;
 import android.telecomm.CallPropertyPresentation;
 import android.telecomm.CallState;
 import android.telecomm.ConnectionRequest;
@@ -31,7 +28,6 @@
 import android.telecomm.PhoneAccount;
 import android.telecomm.Response;
 import android.telecomm.StatusHints;
-import android.telecomm.TelecommConstants;
 import android.telephony.DisconnectCause;
 import android.telephony.PhoneNumberUtils;
 import android.text.TextUtils;
@@ -202,6 +198,12 @@
 
     private boolean mSpeakerphoneOn;
 
+    /**
+     * Tracks the video states which were applicable over the duration of a call.
+     * See {@link android.telecomm.VideoCallProfile} for a list of valid video states.
+     */
+    private int mVideoStateHistory;
+
     private int mVideoState;
 
     /**
@@ -294,7 +296,9 @@
         if (mConnectionService != null && mConnectionService.getComponentName() != null) {
             component = mConnectionService.getComponentName().flattenToShortString();
         }
-        return String.format(Locale.US, "[%s, %s, %s]", mState, component, Log.piiHandle(mHandle));
+
+        return String.format(Locale.US, "[%s, %s, %s, %d]", mState, component,
+                Log.piiHandle(mHandle), getVideoState());
     }
 
     CallState getState() {
@@ -1068,15 +1072,29 @@
     }
 
     /**
-     * At the start of the call, determines the desired video state for the call.
+     * Returns the video states which were applicable over the duration of a call.
+     * See {@link android.telecomm.VideoCallProfile} for a list of valid video states.
+     *
+     * @return The video states applicable over the duration of the call.
+     */
+    public int getVideoStateHistory() {
+        return mVideoStateHistory;
+    }
+
+    /**
+     * Determines the current video state for the call.
+     * For an outgoing call determines the desired video state for the call.
      * Valid values: {@link android.telecomm.VideoCallProfile#VIDEO_STATE_AUDIO_ONLY},
      * {@link android.telecomm.VideoCallProfile#VIDEO_STATE_BIDIRECTIONAL},
      * {@link android.telecomm.VideoCallProfile#VIDEO_STATE_TX_ENABLED},
      * {@link android.telecomm.VideoCallProfile#VIDEO_STATE_RX_ENABLED}.
      *
-     * @param videoState The desired video state for the call.
+     * @param videoState The video state for the call.
      */
     public void setVideoState(int videoState) {
+        // Track which video states were applicable over the duration of the call.
+        mVideoStateHistory = mVideoStateHistory | videoState;
+
         mVideoState = videoState;
         for (Listener l : mListeners) {
             l.onVideoStateChanged(this);
diff --git a/src/com/android/telecomm/CallLogManager.java b/src/com/android/telecomm/CallLogManager.java
index cf7e7ae..d1e2196 100644
--- a/src/com/android/telecomm/CallLogManager.java
+++ b/src/com/android/telecomm/CallLogManager.java
@@ -22,6 +22,7 @@
 import android.provider.CallLog.Calls;
 import android.telecomm.CallState;
 import android.telecomm.PhoneAccount;
+import android.telecomm.VideoCallProfile;
 import android.telephony.PhoneNumberUtils;
 
 import com.android.internal.telephony.CallerInfo;
@@ -120,9 +121,10 @@
         final int presentation = getPresentation(call);
         final PhoneAccount account = call.getPhoneAccount();
 
-        // TODO: Once features and data usage are available, wire them up here.
-        logCall(call.getCallerInfo(), logNumber, presentation, callLogType, Calls.FEATURES_NONE,
-                account, creationTime, age, null);
+        // TODO(vt): Once data usage is available, wire it up here.
+        int callFeatures = getCallFeatures(call.getVideoStateHistory());
+        logCall(call.getCallerInfo(), logNumber, presentation, callLogType, callFeatures, account,
+                creationTime, age, null);
     }
 
     /**
@@ -171,6 +173,20 @@
     }
 
     /**
+     * Based on the video state of the call, determines the call features applicable for the call.
+     *
+     * @param videoState The video state.
+     * @return The call features.
+     */
+    private static int getCallFeatures(int videoState) {
+        if ((videoState & VideoCallProfile.VIDEO_STATE_TX_ENABLED)
+                == VideoCallProfile.VIDEO_STATE_TX_ENABLED) {
+            return Calls.FEATURES_VIDEO;
+        }
+        return Calls.FEATURES_NONE;
+    }
+
+    /**
      * Retrieve the phone number from the call, and then process it before returning the
      * actual number that is to be logged.
      *
diff --git a/src/com/android/telecomm/ConnectionServiceWrapper.java b/src/com/android/telecomm/ConnectionServiceWrapper.java
index a47dc09..fb9d34c 100644
--- a/src/com/android/telecomm/ConnectionServiceWrapper.java
+++ b/src/com/android/telecomm/ConnectionServiceWrapper.java
@@ -76,6 +76,7 @@
     private static final int MSG_SET_STATUS_HINTS = 18;
     private static final int MSG_SET_HANDLE = 19;
     private static final int MSG_SET_CALLER_DISPLAY_NAME = 20;
+    private static final int MSG_SET_VIDEO_STATE = 21;
 
     private final Handler mHandler = new Handler() {
         @Override
@@ -308,6 +309,12 @@
                     }
                     break;
                 }
+                case MSG_SET_VIDEO_STATE: {
+                    call = mCallIdMapper.getCall(msg.obj);
+                    if (call != null) {
+                        call.setVideoState(msg.arg1);
+                    }
+                }
             }
         }
     };
@@ -444,6 +451,13 @@
         }
 
         @Override
+        public void setVideoState(String callId, int videoState) {
+            logIncoming("setVideoState %s %d", callId, videoState);
+            mCallIdMapper.checkValidCallId(callId);
+            mHandler.obtainMessage(MSG_SET_VIDEO_STATE, videoState, 0, callId).sendToTarget();
+        }
+
+        @Override
         public void setAudioModeIsVoip(String callId, boolean isVoip) {
             logIncoming("setAudioModeIsVoip %s %b", callId, isVoip);
             mCallIdMapper.checkValidCallId(callId);
diff --git a/src/com/android/telecomm/TelecommServiceImpl.java b/src/com/android/telecomm/TelecommServiceImpl.java
index f93a7a7..fce9c04 100644
--- a/src/com/android/telecomm/TelecommServiceImpl.java
+++ b/src/com/android/telecomm/TelecommServiceImpl.java
@@ -156,7 +156,7 @@
         PhoneAccount registeredAccount = mPhoneAccountRegistrar.getRegisteredAccount(account);
         if (registeredAccount != null) {
             return new PhoneAccountMetadata(
-                    registeredAccount, 0, account.getComponentName().getPackageName(), null);
+                    registeredAccount, 0, account.getComponentName().getPackageName(), null, false);
         }
         return null;
     }
diff --git a/tests/res/values/donottranslate_strings.xml b/tests/res/values/donottranslate_strings.xml
index 76d8777..91d8628 100644
--- a/tests/res/values/donottranslate_strings.xml
+++ b/tests/res/values/donottranslate_strings.xml
@@ -19,7 +19,7 @@
     <string name="app_name">TelecommTests</string>
 
     <!-- String for the TestCallActivity -->
-    <string name="testCallActivityLabel">Test CallService App</string>
+    <string name="testCallActivityLabel">Test Connection Service App</string>
 
     <!-- String for the TestDialerActivity -->
     <string name="testDialerActivityLabel">Test Dialer</string>
diff --git a/tests/src/com/android/telecomm/testapps/CallNotificationReceiver.java b/tests/src/com/android/telecomm/testapps/CallNotificationReceiver.java
index 72c6fbc..098b065 100644
--- a/tests/src/com/android/telecomm/testapps/CallNotificationReceiver.java
+++ b/tests/src/com/android/telecomm/testapps/CallNotificationReceiver.java
@@ -17,8 +17,12 @@
 package com.android.telecomm.testapps;
 
 import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.os.Bundle;
+import android.telecomm.PhoneAccount;
+import android.telecomm.TelecommConstants;
 
 /**
  * This class receives the notification callback intents used to update call states for
@@ -35,6 +39,10 @@
             "com.android.telecomm.testapps.ACTION_REGISTER_PHONE_ACCOUNT";
     static final String ACTION_SHOW_ALL_PHONE_ACCOUNTS =
             "com.android.telecomm.testapps.ACTION_SHOW_ALL_PHONE_ACCOUNTS";
+    static final String ACTION_VIDEO_CALL =
+            "com.android.telecomm.testapps.ACTION_VIDEO_CALL";
+    static final String ACTION_AUDIO_CALL =
+            "com.android.telecomm.testapps.ACTION_AUDIO_CALL";
 
     /** {@inheritDoc} */
     @Override
@@ -46,6 +54,40 @@
             CallServiceNotifier.getInstance().registerPhoneAccount(context);
         } else if (ACTION_SHOW_ALL_PHONE_ACCOUNTS.equals(action)) {
             CallServiceNotifier.getInstance().showAllPhoneAccounts(context);
+        } else if (ACTION_VIDEO_CALL.equals(action)) {
+            sendIncomingCallIntent(context, true);
+        } else if (ACTION_AUDIO_CALL.equals(action)) {
+            sendIncomingCallIntent(context, false);
         }
     }
+
+    /**
+     * Creates the intent to add an incoming call through Telecomm.
+     *
+     * @param context The current context.
+     * @param isVideoCall {@code True} if this is a video call.
+     */
+    private void sendIncomingCallIntent(Context context, boolean isVideoCall) {
+        // Create intent for adding an incoming call.
+        Intent intent = new Intent(TelecommConstants.ACTION_INCOMING_CALL);
+        // TODO(santoscordon): Use a private @hide permission to make sure this only goes to
+        // Telecomm instead of setting the package explicitly.
+        intent.setPackage("com.android.telecomm");
+
+        PhoneAccount phoneAccount = new PhoneAccount(
+                new ComponentName(context, TestConnectionService.class),
+                null /* id */,
+                null /* handle */,
+                PhoneAccount.CAPABILITY_CALL_PROVIDER);
+        intent.putExtra(TelecommConstants.EXTRA_PHONE_ACCOUNT, phoneAccount);
+
+        // For the purposes of testing, indicate whether the incoming call is a video call by
+        // stashing an indicator in the EXTRA_INCOMING_CALL_EXTRAS.
+        Bundle extras = new Bundle();
+        extras.putBoolean(TestConnectionService.IS_VIDEO_CALL, isVideoCall);
+
+        intent.putExtra(TelecommConstants.EXTRA_INCOMING_CALL_EXTRAS, extras);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        context.startActivity(intent);
+    }
 }
diff --git a/tests/src/com/android/telecomm/testapps/CallServiceNotifier.java b/tests/src/com/android/telecomm/testapps/CallServiceNotifier.java
index 58bdee9..c08f6eb 100644
--- a/tests/src/com/android/telecomm/testapps/CallServiceNotifier.java
+++ b/tests/src/com/android/telecomm/testapps/CallServiceNotifier.java
@@ -23,6 +23,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.net.Uri;
+import android.os.Bundle;
 import android.telecomm.PhoneAccount;
 import android.telecomm.PhoneAccountMetadata;
 import android.telecomm.TelecommConstants;
@@ -92,7 +93,8 @@
                 "testapps_TestConnectionService_Account_ID",
                 Uri.parse("tel:555-TEST"),
                 PhoneAccount.CAPABILITY_CALL_PROVIDER);
-        PhoneAccountMetadata metadata = new PhoneAccountMetadata(phoneAccount, 0, null, null);
+        PhoneAccountMetadata metadata = new PhoneAccountMetadata(phoneAccount, 0, null, null,
+                false);
 
         TelecommManager telecommManager =
                 (TelecommManager) context.getSystemService(Context.TELECOMM_SERVICE);
@@ -122,7 +124,10 @@
      */
     private Notification getPhoneAccountNotification(Context context) {
         final Notification.Builder builder = new Notification.Builder(context);
-        builder.setOngoing(true);
+        // Both notifications have buttons and only the first one with buttons will show its
+        // buttons.  Since the phone accounts notification is always first, setting false ensures
+        // it can be dismissed to use the other notification.
+        builder.setOngoing(false);
         builder.setPriority(Notification.PRIORITY_HIGH);
 
         final PendingIntent intent = createShowAllPhoneAccountsIntent(context);
@@ -146,16 +151,12 @@
         final Notification.Builder builder = new Notification.Builder(context);
         builder.setOngoing(true);
         builder.setPriority(Notification.PRIORITY_HIGH);
-
-        final PendingIntent intent = createIncomingCallIntent(context, false /* isVideoCall */);
-        builder.setContentIntent(intent);
-
         builder.setSmallIcon(android.R.drawable.stat_sys_phone_call);
         builder.setContentText("Test calls via CallService API");
-        builder.setContentTitle("TestConnectionService");
+        builder.setContentTitle("Test Connection Service");
 
-        addAddCallAction(builder, context);
         addAddVideoCallAction(builder, context);
+        addAddCallAction(builder, context);
         addExitAction(builder, context);
 
         return builder.build();
@@ -190,27 +191,21 @@
     }
 
     /**
-     * Creates the intent to add an incoming call through Telecomm.
+     * Creates the intent to start an incoming video call
      */
-    private PendingIntent createIncomingCallIntent(Context context, boolean isVideoCall) {
-        log("Creating incoming call pending intent.");
+    private PendingIntent createIncomingVideoCall(Context context) {
+        final Intent intent = new Intent(CallNotificationReceiver.ACTION_VIDEO_CALL,
+                null, context, CallNotificationReceiver.class);
+        return PendingIntent.getBroadcast(context, 0, intent, 0);
+    }
 
-        // Create intent for adding an incoming call.
-        Intent intent = new Intent(TelecommConstants.ACTION_INCOMING_CALL);
-        // TODO(santoscordon): Use a private @hide permission to make sure this only goes to
-        // Telecomm instead of setting the package explicitly.
-        intent.setPackage("com.android.telecomm");
-
-        PhoneAccount phoneAccount = new PhoneAccount(
-                new ComponentName(context, TestConnectionService.class),
-                null /* id */,
-                null /* handle */,
-                PhoneAccount.CAPABILITY_CALL_PROVIDER);
-        intent.putExtra(TelecommConstants.EXTRA_PHONE_ACCOUNT, phoneAccount);
-
-        mStartVideoCall = isVideoCall;
-
-        return PendingIntent.getActivity(context, 0, intent, 0);
+    /**
+     * Creates the intent to start an incoming audio call
+     */
+    private PendingIntent createIncomingAudioCall(Context context) {
+        final Intent intent = new Intent(CallNotificationReceiver.ACTION_AUDIO_CALL,
+                null, context, CallNotificationReceiver.class);
+        return PendingIntent.getBroadcast(context, 0, intent, 0);
     }
 
     /**
@@ -218,15 +213,14 @@
      * @param builder The Notification Builder.
      */
     private void addAddCallAction(Notification.Builder builder, Context context) {
-        // Set pending intent on the notification builder.
-        builder.addAction(0, "Add Call", createIncomingCallIntent(context, false /* isVideoCall */));
+        builder.addAction(0, "Add Call", createIncomingAudioCall(context));
     }
 
     /**
      * Adds an action to the Notification Builder to add an incoming video call through Telecomm.
      */
     private void addAddVideoCallAction(Notification.Builder builder, Context context) {
-        builder.addAction(0, "Add Video", createIncomingCallIntent(context, true /* isVideoCall */));
+        builder.addAction(0, "Add Video", createIncomingVideoCall(context));
     }
 
     /**
diff --git a/tests/src/com/android/telecomm/testapps/TestConnectionService.java b/tests/src/com/android/telecomm/testapps/TestConnectionService.java
index 9189d73..a80109c 100644
--- a/tests/src/com/android/telecomm/testapps/TestConnectionService.java
+++ b/tests/src/com/android/telecomm/testapps/TestConnectionService.java
@@ -39,6 +39,7 @@
 
 import com.android.telecomm.tests.R;
 
+import java.lang.String;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
@@ -53,6 +54,12 @@
     public static final String EXTRA_GATEWAY_ORIGINAL_URI =
             "com.android.phone.extra.GATEWAY_ORIGINAL_URI";
 
+    /**
+     * Intent extra used to pass along whether a call is video or audio based on the user's choice
+     * in the notification.
+     */
+    public static final String IS_VIDEO_CALL = "IsVideoCall";
+
     private final class TestConnection extends Connection {
         private final RemoteConnection.Listener mProxyListener = new RemoteConnection.Listener() {
             @Override
@@ -94,6 +101,11 @@
             }
 
             @Override
+            public void onVideoStateChanged(RemoteConnection connection, int videoState) {
+                setVideoState(videoState);
+            }
+
+            @Override
             public void onHandleChanged(RemoteConnection connection, Uri handle, int presentation) {
                 setHandle(handle, presentation);
             }
@@ -252,6 +264,7 @@
                         mIsIncoming ? Connection.State.RINGING: Connection.State.DIALING);
 
                 mCalls.add(connection);
+
                 ConnectionRequest remoteRequest = new ConnectionRequest(
                         request.getAccount(),
                         mOriginalRequest.getCallId(),
@@ -362,6 +375,7 @@
         Bundle extras = originalRequest.getExtras();
         String gatewayPackage = extras.getString(EXTRA_GATEWAY_PROVIDER_PACKAGE);
         Uri originalHandle = extras.getParcelable(EXTRA_GATEWAY_ORIGINAL_URI);
+
         log("gateway package [" + gatewayPackage + "], original handle [" +
                 originalHandle + "]");
 
@@ -382,6 +396,7 @@
 
             TestConnection connection = new TestConnection(null, Connection.State.DIALING);
             mCalls.add(connection);
+
             callback.onSuccess(request, connection);
             connection.startOutgoing();
         } else {
@@ -412,16 +427,20 @@
         if (account != null && componentName.equals(account.getComponentName())) {
             // Use dummy number for testing incoming calls.
             Uri handle = Uri.fromParts(SCHEME_TEL, "5551234", null);
-            boolean isVideoCall = CallServiceNotifier.getInstance().shouldStartVideoCall();
 
-            TestConnection connection = new TestConnection(null, Connection.State.DIALING);
+            // Get the stashed intent extra that determines if this is a video call or audio call.
+            Bundle extras = request.getExtras();
+            boolean isVideoCall = extras.getBoolean(IS_VIDEO_CALL);
+
+            TestConnection connection = new TestConnection(null, Connection.State.RINGING);
             if (isVideoCall) {
                 connection.setCallVideoProvider(new TestCallVideoProvider(getApplicationContext()));
             }
-
-            mCalls.add(connection);
             int videoState = isVideoCall ?
-                    VideoCallProfile.VIDEO_STATE_BIDIRECTIONAL : request.getVideoState();
+                    VideoCallProfile.VIDEO_STATE_BIDIRECTIONAL :
+                    VideoCallProfile.VIDEO_STATE_AUDIO_ONLY;
+            mCalls.add(connection);
+
             ConnectionRequest newRequest = new ConnectionRequest(
                     request.getAccount(),
                     request.getCallId(),
@@ -430,6 +449,7 @@
                     request.getExtras(),
                     videoState);
             response.onSuccess(newRequest, connection);
+            connection.setVideoState(videoState);
         } else {
             SimpleResponse<Uri, List<PhoneAccount>> accountResponse =
                     new SimpleResponse<Uri, List<PhoneAccount>>() {