Merge "Change isRinging and isInAPhoneCall to execute from binder thread."
diff --git a/src/com/android/telecomm/CallLogManager.java b/src/com/android/telecomm/CallLogManager.java
index 142e43b..712551e 100644
--- a/src/com/android/telecomm/CallLogManager.java
+++ b/src/com/android/telecomm/CallLogManager.java
@@ -42,20 +42,25 @@
          * @param presentation Number presentation of the phone number to be logged.
          * @param callType The type of call (e.g INCOMING_TYPE). @see
          *     {@link android.provider.CallLog} for the list of values.
+         * @param features The features of the call (e.g. FEATURES_VIDEO). @see
+         *     {@link android.provider.CallLog} for the list of values.
          * @param creationDate Time when the call was created (milliseconds since epoch).
          * @param durationInMillis Duration of the call (milliseconds).
+         * @param dataUsage Data usage in bytes, or null if not applicable.
          */
         public AddCallArgs(Context context, ContactInfo contactInfo, String number,
-                int presentation, int callType, PhoneAccount account,
-                long creationDate, long durationInMillis) {
+                int presentation, int callType, int features, PhoneAccount account,
+                long creationDate, long durationInMillis, Long dataUsage) {
             this.context = context;
             this.contactInfo = contactInfo;
             this.number = number;
             this.presentation = presentation;
             this.callType = callType;
+            this.features = features;
             this.mAccount = account;
             this.timestamp = creationDate;
             this.durationInSec = (int)(durationInMillis / 1000);
+            this.dataUsage = dataUsage;
         }
         // Since the members are accessed directly, we don't use the
         // mXxxx notation.
@@ -64,9 +69,11 @@
         public final String number;
         public final int presentation;
         public final int callType;
+        public final int features;
         public final PhoneAccount mAccount;
         public final long timestamp;
         public final int durationInSec;
+        public final Long dataUsage;
     }
 
     private static final String TAG = CallLogManager.class.getSimpleName();
@@ -114,7 +121,9 @@
         final int presentation = getPresentation(call, contactInfo);
         final PhoneAccount account = call.getPhoneAccount();
 
-        logCall(contactInfo, logNumber, presentation, callLogType, account, creationTime, age);
+        // TODO: Once features and data usage are available, wire them up here.
+        logCall(contactInfo, logNumber, presentation, callLogType, Calls.FEATURES_NONE, account,
+                creationTime, age, null);
     }
 
     /**
@@ -124,17 +133,21 @@
      * @param number The number the call was made to or from.
      * @param presentation
      * @param callType The type of call.
+     * @param features The features of the call.
      * @param start The start time of the call, in milliseconds.
      * @param duration The duration of the call, in milliseconds.
+     * @param dataUsage The data usage for the call, null if not applicable.
      */
     private void logCall(
             ContactInfo contactInfo,
             String number,
             int presentation,
             int callType,
+            int features,
             PhoneAccount account,
             long start,
-            long duration) {
+            long duration,
+            Long dataUsage) {
         boolean isEmergencyNumber = PhoneNumberUtils.isLocalEmergencyNumber(mContext, number);
 
         // On some devices, to avoid accidental redialing of emergency numbers, we *never* log
@@ -151,7 +164,7 @@
                     + Log.pii(number) + "," + presentation + ", " + callType
                     + ", " + start + ", " + duration);
             AddCallArgs args = new AddCallArgs(mContext, contactInfo, number, presentation,
-                    callType, account, start, duration);
+                    callType, features, account, start, duration, dataUsage);
             logCallAsync(args);
         } else {
           Log.d(TAG, "Not adding emergency call to call log.");
@@ -223,7 +236,8 @@
                 try {
                     // May block.
                     result[i] = Calls.addCall(null, c.context, c.number, c.presentation,
-                            c.callType, c.mAccount, c.timestamp, c.durationInSec);
+                            c.callType, c.features, c.mAccount, c.timestamp, c.durationInSec,
+                            c.dataUsage);
                 } catch (Exception e) {
                     // This is very rare but may happen in legitimate cases.
                     // E.g. If the phone is encrypted and thus write request fails, it may cause
diff --git a/src/com/android/telecomm/ConnectionServiceWrapper.java b/src/com/android/telecomm/ConnectionServiceWrapper.java
index b2dd085..9d59aed 100644
--- a/src/com/android/telecomm/ConnectionServiceWrapper.java
+++ b/src/com/android/telecomm/ConnectionServiceWrapper.java
@@ -482,7 +482,7 @@
 
         @Override
         public void setAudioModeIsVoip(String callId, boolean isVoip) {
-            logIncoming("setAudioModeIsVoip %s %d", callId, isVoip);
+            logIncoming("setAudioModeIsVoip %s %b", callId, isVoip);
             mCallIdMapper.checkValidCallId(callId);
             mHandler.obtainMessage(MSG_SET_AUDIO_MODE_IS_VOIP, isVoip ? 1 : 0, 0,
                     callId).sendToTarget();
diff --git a/src/com/android/telecomm/OutgoingCallProcessor.java b/src/com/android/telecomm/OutgoingCallProcessor.java
index c33b17e..1f6e4f3 100644
--- a/src/com/android/telecomm/OutgoingCallProcessor.java
+++ b/src/com/android/telecomm/OutgoingCallProcessor.java
@@ -16,6 +16,7 @@
 
 package com.android.telecomm;
 
+import android.content.ComponentName;
 import android.net.Uri;
 import android.os.Handler;
 import android.os.Message;
@@ -196,8 +197,12 @@
         for (ConnectionServiceWrapper service : services) {
             CallServiceDescriptor descriptor = service.getDescriptor();
             // TODO(sail): Remove once there's a way to pick the service.
-            if (descriptor.getServiceComponent().getPackageName().equals(
-                    "com.google.android.talk")) {
+            ComponentName sipName = new ComponentName("com.android.phone",
+                    "com.android.services.telephony.sip.SipConnectionService");
+            ComponentName hangoutsName = new ComponentName("com.google.android.talk",
+                    "com.google.android.apps.babel.telephony.TeleConnectionService");
+            ComponentName serviceName = descriptor.getServiceComponent();
+            if (serviceName.equals(sipName) || serviceName.equals(hangoutsName)) {
                 Log.i(this, "Moving connection service %s to top of list", descriptor);
                 mCallServiceDescriptors.add(0, descriptor);
             } else {
diff --git a/tests/src/com/android/telecomm/testapps/CallServiceNotifier.java b/tests/src/com/android/telecomm/testapps/CallServiceNotifier.java
index ff52157..60f4250 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.Intent;
 import android.telecomm.CallServiceDescriptor;
 import android.telecomm.TelecommConstants;
+import android.telecomm.VideoCallProfile;
 import android.util.Log;
 
 /**
@@ -38,6 +39,12 @@
     private static final int CALL_NOTIFICATION_ID = 1;
 
     /**
+     * Whether the added call should be started as a video call. Referenced by
+     * {@link TestConnectionService} to know whether to provide a call video provider.
+     */
+    public static boolean mStartVideoCall;
+
+    /**
      * Singleton accessor.
      */
     public static CallServiceNotifier getInstance() {
@@ -81,7 +88,7 @@
         builder.setOngoing(true);
         builder.setPriority(Notification.PRIORITY_HIGH);
 
-        final PendingIntent intent = createIncomingCallIntent(context);
+        final PendingIntent intent = createIncomingCallIntent(context, false /* isVideoCall */);
         builder.setContentIntent(intent);
 
         builder.setSmallIcon(android.R.drawable.stat_sys_phone_call);
@@ -89,6 +96,7 @@
         builder.setContentTitle("TestConnectionService");
 
         addAddCallAction(builder, context);
+        addAddVideoCallAction(builder, context);
         addExitAction(builder, context);
 
         return builder.build();
@@ -107,7 +115,7 @@
     /**
      * Creates the intent to add an incoming call through Telecomm.
      */
-    private PendingIntent createIncomingCallIntent(Context context) {
+    private PendingIntent createIncomingCallIntent(Context context, boolean isVideoCall) {
         log("Creating incoming call pending intent.");
         // Build descriptor for TestConnectionService.
         CallServiceDescriptor.Builder descriptorBuilder = CallServiceDescriptor.newBuilder(context);
@@ -121,6 +129,8 @@
         intent.setPackage("com.android.telecomm");
         intent.putExtra(TelecommConstants.EXTRA_CALL_SERVICE_DESCRIPTOR, descriptorBuilder.build());
 
+        mStartVideoCall = isVideoCall;
+
         return PendingIntent.getActivity(context, 0, intent, 0);
     }
 
@@ -130,7 +140,14 @@
      */
     private void addAddCallAction(Notification.Builder builder, Context context) {
         // Set pending intent on the notification builder.
-        builder.addAction(0, "Add a Call", createIncomingCallIntent(context));
+        builder.addAction(0, "Add Call", createIncomingCallIntent(context, false /* isVideoCall */));
+    }
+
+    /**
+     * 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 */));
     }
 
     /**
@@ -140,6 +157,10 @@
         builder.addAction(0, "Exit", createExitIntent(context));
     }
 
+    public boolean shouldStartVideoCall() {
+        return mStartVideoCall;
+    }
+
     private static void log(String msg) {
         Log.w("testcallservice", "[CallServiceNotifier] " + msg);
     }
diff --git a/tests/src/com/android/telecomm/testapps/TestCallVideoProvider.java b/tests/src/com/android/telecomm/testapps/TestCallVideoProvider.java
index 1c502f4..5b673ad 100644
--- a/tests/src/com/android/telecomm/testapps/TestCallVideoProvider.java
+++ b/tests/src/com/android/telecomm/testapps/TestCallVideoProvider.java
@@ -16,6 +16,10 @@
 
 package com.android.telecomm.testapps;
 
+import android.content.Context;
+import android.os.RemoteException;
+import android.telecomm.CallCameraCapabilities;
+import android.telecomm.CallVideoClient;
 import android.telecomm.CallVideoProvider;
 import android.telecomm.RemoteCallVideoClient;
 import android.telecomm.VideoCallProfile;
@@ -23,14 +27,28 @@
 import android.util.Log;
 import android.view.Surface;
 
+import java.util.Random;
+
 /**
  * Implements the CallVideoProvider.
  */
 public class TestCallVideoProvider extends CallVideoProvider {
+    private RemoteCallVideoClient mCallVideoClient;
+    private CallCameraCapabilities mCapabilities;
+    private Random random;
 
+
+    public TestCallVideoProvider(Context context) {
+        mCapabilities = new CallCameraCapabilities(false /* zoomSupported */, 0 /* maxZoom */);
+        random = new Random();
+    }
+
+    /**
+     * Save the reference to the CallVideoClient so callback can be invoked.
+     */
     @Override
     public void onSetCallVideoClient(RemoteCallVideoClient callVideoClient) {
-
+        mCallVideoClient = callVideoClient;
     }
 
     @Override
@@ -40,27 +58,56 @@
 
     @Override
     public void onSetPreviewSurface(Surface surface) {
-
+        log("Set preview surface");
     }
 
     @Override
     public void onSetDisplaySurface(Surface surface) {
-
+        log("Set display surface");
     }
 
     @Override
     public void onSetDeviceOrientation(int rotation) {
-
+        log("Set device orientation");
     }
 
+    /**
+     * Sets the zoom value, creating a new CallCameraCapabalities object. If the zoom value is
+     * non-positive, assume that zoom is not supported.
+     */
     @Override
     public void onSetZoom(float value) {
+        log("Set zoom to " + value);
 
+        if (value <= 0) {
+            mCapabilities = new CallCameraCapabilities(false /* zoomSupported */, 0 /* maxZoom */);
+        } else {
+            mCapabilities = new CallCameraCapabilities(true /* zoomSupported */, value);
+        }
+
+        try {
+            mCallVideoClient.handleCameraCapabilitiesChange(mCapabilities);
+        } catch (RemoteException ignored) {
+        }
     }
 
+    /**
+     * "Sends" a request with a video call profile. Assumes that this response succeeds and sends
+     * the response back via the CallVideoClient.
+     */
     @Override
     public void onSendSessionModifyRequest(VideoCallProfile requestProfile) {
+        log("Sent session modify request");
 
+        VideoCallProfile responseProfile = new VideoCallProfile(
+                requestProfile.getVideoState(), requestProfile.getQuality());
+        try {
+            mCallVideoClient.receiveSessionModifyResponse(
+                    CallVideoClient.SESSION_MODIFY_REQUEST_SUCCESS,
+                    requestProfile,
+                    responseProfile);
+        } catch (RemoteException ignored) {
+        }
     }
 
     @Override
@@ -68,22 +115,40 @@
 
     }
 
+    /**
+     * Returns a CallCameraCapabilities object without supporting zoom.
+     */
     @Override
     public void onRequestCameraCapabilities() {
-
+        log("Requested camera capabilities");
+        try {
+            mCallVideoClient.handleCameraCapabilitiesChange(mCapabilities);
+        } catch (RemoteException ignored) {
+        }
     }
 
+    /**
+     * Randomly reports data usage of value ranging from 10MB to 60MB.
+     */
     @Override
     public void onRequestCallDataUsage() {
-
+        log("Requested call data usage");
+        int dataUsageKb = (10 *1024) + random.nextInt(50 * 1024);
+        try {
+            mCallVideoClient.updateCallDataUsage(dataUsageKb);
+        } catch (RemoteException ignored) {
+        }
     }
 
+    /**
+     * We do not have a need to set a paused image.
+     */
     @Override
     public void onSetPauseImage(String uri) {
-
+        // Not implemented.
     }
 
     private static void log(String msg) {
         Log.w("TestCallServiceProvider", "[TestCallServiceProvider] " + msg);
     }
-}
+}
\ No newline at end of file
diff --git a/tests/src/com/android/telecomm/testapps/TestConnectionService.java b/tests/src/com/android/telecomm/testapps/TestConnectionService.java
index e84b461..f24f779 100644
--- a/tests/src/com/android/telecomm/testapps/TestConnectionService.java
+++ b/tests/src/com/android/telecomm/testapps/TestConnectionService.java
@@ -10,7 +10,7 @@
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- Ca* See the License for the specific language governing permissions and
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
@@ -30,6 +30,8 @@
 import android.telecomm.Response;
 import android.telecomm.SimpleResponse;
 import android.telecomm.StatusHints;
+import android.telecomm.PhoneAccount;
+import android.telecomm.VideoCallProfile;
 import android.telephony.DisconnectCause;
 import android.text.TextUtils;
 import android.util.Log;
@@ -236,6 +238,7 @@
             if (remoteConnection != null) {
                 TestConnection connection = new TestConnection(
                         remoteConnection, Connection.State.DIALING);
+
                 mCalls.add(connection);
                 mCallback.onSuccess(mOriginalRequest, connection);
             } else {
@@ -298,7 +301,7 @@
         mCalls.remove(connection);
 
         // Stops audio if there are no more calls.
-        if (mCalls.isEmpty() && mMediaPlayer.isPlaying()) {
+        if (mCalls.isEmpty() && mMediaPlayer != null && mMediaPlayer.isPlaying()) {
             mMediaPlayer.stop();
             mMediaPlayer.release();
             mMediaPlayer = createMediaPlayer();
@@ -375,15 +378,21 @@
     @Override
     public void onCreateIncomingConnection(
             ConnectionRequest request, Response<ConnectionRequest, Connection> callback) {
-
         // 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);
+        if (isVideoCall) {
+            connection.setCallVideoProvider(new TestCallVideoProvider(getApplicationContext()));
+        }
+
         mCalls.add(connection);
-        callback.onResult(
-                new ConnectionRequest(request.getCallId(), handle, request.getExtras(),
-                        request.getVideoState()),
-                connection);
+
+        ConnectionRequest newRequest = new ConnectionRequest(request.getCallId(), handle,
+                request.getExtras(),
+                isVideoCall ? VideoCallProfile.VIDEO_STATE_BIDIRECTIONAL : request.getVideoState());
+
+        callback.onResult(newRequest, connection);
     }
 }