Merge "Update permissions around showCallScreen."
diff --git a/src/com/android/telecomm/Call.java b/src/com/android/telecomm/Call.java
index 3d4771b..5785ee7 100644
--- a/src/com/android/telecomm/Call.java
+++ b/src/com/android/telecomm/Call.java
@@ -29,6 +29,7 @@
 import android.telecomm.GatewayInfo;
 import android.telecomm.PhoneAccount;
 import android.telecomm.Response;
+import android.telecomm.StatusHints;
 import android.telecomm.TelecommConstants;
 import android.telephony.DisconnectCause;
 import android.telephony.PhoneNumberUtils;
@@ -55,7 +56,6 @@
  *  connected etc).
  */
 final class Call implements OutgoingCallResponse {
-
     /**
      * Listener for events on the call.
      */
@@ -76,6 +76,8 @@
         void onCallVideoProviderChanged(Call call);
         void onFeaturesChanged(Call call);
         void onCallerInfoChanged(Call call);
+        void onAudioModeIsVoipChanged(Call call);
+        void onStatusHintsChanged(Call call);
     }
 
     abstract static class ListenerBase implements Listener {
@@ -111,6 +113,10 @@
         public void onFeaturesChanged(Call call) {}
         @Override
         public void onCallerInfoChanged(Call call) {}
+        @Override
+        public void onAudioModeIsVoipChanged(Call call) {}
+        @Override
+        public void onStatusHintsChanged(Call call) {}
     }
 
     private static final OnQueryCompleteListener sCallerInfoQueryListener =
@@ -153,7 +159,7 @@
      * service. */
     private final GatewayInfo mGatewayInfo;
 
-    private final PhoneAccount mAccount;
+    private PhoneAccount mPhoneAccount;
 
     private final Handler mHandler = new Handler();
 
@@ -174,6 +180,8 @@
 
     private boolean mSpeakerphoneOn;
 
+    private int mVideoState;
+
     /**
      * Disconnect cause for the call. Only valid if the state of the call is DISCONNECTED.
      * See {@link android.telephony.DisconnectCause}.
@@ -227,6 +235,9 @@
     /** Features associated with the call which the InCall UI may wish to show icons for. */
     private int mFeatures;
 
+    private boolean mAudioModeIsVoip;
+    private StatusHints mStatusHints;
+
     /**
      * Creates an empty call object.
      *
@@ -249,7 +260,7 @@
         mState = isConference ? CallState.ACTIVE : CallState.NEW;
         setHandle(handle);
         mGatewayInfo = gatewayInfo;
-        mAccount = account;
+        mPhoneAccount = account;
         mIsIncoming = isIncoming;
         mIsConference = isConference;
         maybeLoadCannedSmsResponses();
@@ -375,8 +386,8 @@
         return mGatewayInfo;
     }
 
-    PhoneAccount getAccount() {
-        return mAccount;
+    PhoneAccount getPhoneAccount() {
+        return mPhoneAccount;
     }
 
     boolean isIncoming() {
@@ -481,6 +492,8 @@
      * in-call UI.
      */
     void handleVerifiedIncoming(ConnectionRequest request) {
+        mPhoneAccount = request.getAccount();
+
         // We do not handle incoming calls immediately when they are verified by the connection
         // service. We allow the caller-info-query code to execute first so that we can read the
         // direct-to-voicemail property before deciding if we want to show the incoming call to the
@@ -1031,4 +1044,52 @@
             l.onFeaturesChanged(Call.this);
         }
     }
+
+    /**
+     * The current 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}.
+     *
+     * @return True if video is enabled.
+     */
+    public int getVideoState() {
+        return mVideoState;
+    }
+
+    /**
+     * At the start of the 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.
+     */
+    public void setVideoState(int videoState) {
+        mVideoState = videoState;
+    }
+
+    public boolean getAudioModeIsVoip() {
+        return mAudioModeIsVoip;
+    }
+
+    public void setAudioModeIsVoip(boolean audioModeIsVoip) {
+        mAudioModeIsVoip = audioModeIsVoip;
+        for (Listener l : mListeners) {
+            l.onAudioModeIsVoipChanged(this);
+        }
+    }
+
+    public StatusHints getStatusHints() {
+        return mStatusHints;
+    }
+
+    public void setStatusHints(StatusHints statusHints) {
+        mStatusHints = statusHints;
+        for (Listener l : mListeners) {
+            l.onStatusHintsChanged(this);
+        }
+    }
 }
diff --git a/src/com/android/telecomm/CallAudioManager.java b/src/com/android/telecomm/CallAudioManager.java
index 35de0cc..8156db0 100644
--- a/src/com/android/telecomm/CallAudioManager.java
+++ b/src/com/android/telecomm/CallAudioManager.java
@@ -102,6 +102,11 @@
         updateAudioForForegroundCall();
     }
 
+    @Override
+    public void onAudioModeIsVoipChanged(Call call) {
+        updateAudioStreamAndMode();
+    }
+
     void toggleMute() {
         mute(!mAudioState.isMuted);
     }
@@ -277,8 +282,8 @@
         } else {
             Call call = getForegroundCall();
             if (call != null) {
-                int mode = TelephonyUtil.isCurrentlyPSTNCall(call) ?
-                        AudioManager.MODE_IN_CALL : AudioManager.MODE_IN_COMMUNICATION;
+                int mode = call.getAudioModeIsVoip() ?
+                        AudioManager.MODE_IN_COMMUNICATION : AudioManager.MODE_IN_CALL;
                 requestAudioFocusAndSetMode(AudioManager.STREAM_VOICE_CALL, mode);
             } else if (mIsTonePlaying) {
                 // There is no call, however, we are still playing a tone, so keep focus.
diff --git a/src/com/android/telecomm/CallLogManager.java b/src/com/android/telecomm/CallLogManager.java
index 906ecd4..142e43b 100644
--- a/src/com/android/telecomm/CallLogManager.java
+++ b/src/com/android/telecomm/CallLogManager.java
@@ -112,7 +112,7 @@
         Log.d(TAG, "logNumber set to: %s", Log.pii(logNumber));
 
         final int presentation = getPresentation(call, contactInfo);
-        final PhoneAccount account = call.getAccount();
+        final PhoneAccount account = call.getPhoneAccount();
 
         logCall(contactInfo, logNumber, presentation, callLogType, account, creationTime, age);
     }
diff --git a/src/com/android/telecomm/CallsManager.java b/src/com/android/telecomm/CallsManager.java
index f78fb7c..ec23222 100644
--- a/src/com/android/telecomm/CallsManager.java
+++ b/src/com/android/telecomm/CallsManager.java
@@ -23,15 +23,13 @@
 import android.telecomm.CallState;
 import android.telecomm.GatewayInfo;
 import android.telecomm.PhoneAccount;
+import android.telecomm.StatusHints;
 import android.telephony.DisconnectCause;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableCollection;
 import com.google.common.collect.ImmutableList;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
 import java.util.HashSet;
 import java.util.LinkedHashSet;
 import java.util.Set;
@@ -64,6 +62,8 @@
         void onCannedSmsResponsesLoaded(Call call);
         void onCallVideoProviderChanged(Call call);
         void onFeaturesChanged(Call call);
+        void onAudioModeIsVoipChanged(Call call);
+        void onStatusHintsChanged(Call call);
     }
 
     private static final CallsManager INSTANCE = new CallsManager();
@@ -229,6 +229,20 @@
         }
     }
 
+    @Override
+    public void onAudioModeIsVoipChanged(Call call) {
+        for (CallsManagerListener listener : mListeners) {
+            listener.onAudioModeIsVoipChanged(call);
+        }
+    }
+
+    @Override
+    public void onStatusHintsChanged(Call call) {
+        for (CallsManagerListener listener : mListeners) {
+            listener.onStatusHintsChanged(call);
+        }
+    }
+
     ImmutableCollection<Call> getCalls() {
         return ImmutableList.copyOf(mCalls);
     }
@@ -286,9 +300,11 @@
      * @param gatewayInfo Optional gateway information that can be used to route the call to the
      *         actual dialed handle via a gateway provider. May be null.
      * @param speakerphoneOn Whether or not to turn the speakerphone on once the call connects.
+     * @param videoState The desired video state for the outgoing call.
      */
     void placeOutgoingCall(Uri handle, ContactInfo contactInfo, GatewayInfo gatewayInfo,
-            PhoneAccount account, boolean speakerphoneOn) {
+            PhoneAccount account, boolean speakerphoneOn, int videoState) {
+
         final Uri uriHandle = (gatewayInfo == null) ? handle : gatewayInfo.getGatewayHandle();
 
         if (gatewayInfo == null) {
@@ -302,6 +318,7 @@
                 uriHandle, gatewayInfo, account,
                 false /* isIncoming */, false /* isConference */);
         call.setStartWithSpeakerphoneOn(speakerphoneOn);
+        call.setVideoState(videoState);
 
         // TODO(santoscordon): Move this to be a part of addCall()
         call.addListener(this);
diff --git a/src/com/android/telecomm/CallsManagerListenerBase.java b/src/com/android/telecomm/CallsManagerListenerBase.java
index f34bdad..77dc7b6 100644
--- a/src/com/android/telecomm/CallsManagerListenerBase.java
+++ b/src/com/android/telecomm/CallsManagerListenerBase.java
@@ -20,6 +20,7 @@
 import android.telecomm.CallAudioState;
 import android.telecomm.CallServiceDescriptor;
 import android.telecomm.CallState;
+import android.telecomm.StatusHints;
 
 /**
  * Provides a default implementation for listeners of CallsManager.
@@ -83,4 +84,12 @@
     @Override
     public void onFeaturesChanged(Call call) {
     }
+
+    @Override
+    public void onAudioModeIsVoipChanged(Call call) {
+    }
+
+    @Override
+    public void onStatusHintsChanged(Call call) {
+    }
 }
diff --git a/src/com/android/telecomm/ConnectionServiceWrapper.java b/src/com/android/telecomm/ConnectionServiceWrapper.java
index 00eb6d5..e355890 100644
--- a/src/com/android/telecomm/ConnectionServiceWrapper.java
+++ b/src/com/android/telecomm/ConnectionServiceWrapper.java
@@ -27,11 +27,11 @@
 import android.telecomm.CallServiceDescriptor;
 import android.telecomm.ConnectionRequest;
 import android.telecomm.GatewayInfo;
+import android.telecomm.StatusHints;
 import android.telecomm.TelecommConstants;
 import android.telephony.DisconnectCause;
 
 import com.android.internal.os.SomeArgs;
-
 import com.android.internal.telecomm.IConnectionService;
 import com.android.internal.telecomm.IConnectionServiceAdapter;
 import com.android.internal.telecomm.ICallServiceProvider;
@@ -76,6 +76,8 @@
     private static final int MSG_QUERY_REMOTE_CALL_SERVICES = 16;
     private static final int MSG_SET_CALL_VIDEO_PROVIDER = 17;
     private static final int MSG_SET_FEATURES = 18;
+    private static final int MSG_SET_AUDIO_MODE_IS_VOIP = 19;
+    private static final int MSG_SET_STATUS_HINTS = 20;
 
     private final Handler mHandler = new Handler() {
         @Override
@@ -288,7 +290,7 @@
                     SomeArgs args = (SomeArgs) msg.obj;
                     try {
                         call = mCallIdMapper.getCall(args.arg1);
-                        int features = (int) args.arg2;
+                        int features = (int) args.argi1;
                         if (call != null) {
                             call.setFeatures(features);
                         }
@@ -297,6 +299,32 @@
                     }
                     break;
                 }
+                case MSG_SET_AUDIO_MODE_IS_VOIP: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    try {
+                        call = mCallIdMapper.getCall(args.arg1);
+                        boolean isVoip = args.argi1 == 1;
+                        if (call != null) {
+                            call.setAudioModeIsVoip(isVoip);
+                        }
+                    } finally {
+                        args.recycle();
+                    }
+                    break;
+                }
+                case MSG_SET_STATUS_HINTS: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    try {
+                        call = mCallIdMapper.getCall(args.arg1);
+                        StatusHints statusHints = (StatusHints) args.arg2;
+                        if (call != null) {
+                            call.setStatusHints(statusHints);
+                        }
+                    } finally {
+                        args.recycle();
+                    }
+                    break;
+                }
             }
         }
     };
@@ -463,9 +491,29 @@
             mCallIdMapper.checkValidCallId(callId);
             SomeArgs args = SomeArgs.obtain();
             args.arg1 = callId;
-            args.arg2 = features;
+            args.argi1 = features;
             mHandler.obtainMessage(MSG_SET_FEATURES, args).sendToTarget();
         }
+
+        @Override
+        public void setAudioModeIsVoip(String callId, boolean isVoip) {
+            logIncoming("setAudioModeIsVoip %s %d", callId, isVoip);
+            mCallIdMapper.checkValidCallId(callId);
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = callId;
+            args.argi1 = isVoip ? 1 : 0;
+            mHandler.obtainMessage(MSG_SET_AUDIO_MODE_IS_VOIP, args).sendToTarget();
+        }
+
+        @Override
+        public void setStatusHints(String callId, StatusHints statusHints) {
+            logIncoming("setStatusHints %s %s", callId, statusHints);
+            mCallIdMapper.checkValidCallId(callId);
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = callId;
+            args.arg2 = statusHints;
+            mHandler.obtainMessage(MSG_SET_STATUS_HINTS, args).sendToTarget();
+        }
     }
 
     private final Adapter mAdapter = new Adapter();
@@ -538,7 +586,8 @@
                             NewOutgoingCallIntentBroadcaster.EXTRA_GATEWAY_ORIGINAL_URI,
                             gatewayInfo.getOriginalHandle());
                 }
-                ConnectionRequest request = new ConnectionRequest(callId, call.getHandle(), extras);
+                ConnectionRequest request = new ConnectionRequest(callId, call.getHandle(), extras,
+                        call.getVideoState());
 
                 try {
                     mServiceInterface.call(request);
@@ -631,7 +680,7 @@
                     String callId = mCallIdMapper.getCallId(call);
                     logOutgoing("createIncomingCall %s %s", callId, extras);
                     ConnectionRequest request = new ConnectionRequest(
-                            callId, call.getHandle(), extras);
+                            callId, call.getHandle(), extras, call.getVideoState());
                     try {
                         mServiceInterface.createIncomingCall(request);
                     } catch (RemoteException e) {
diff --git a/src/com/android/telecomm/InCallController.java b/src/com/android/telecomm/InCallController.java
index d1215ae..42d6a03 100644
--- a/src/com/android/telecomm/InCallController.java
+++ b/src/com/android/telecomm/InCallController.java
@@ -159,6 +159,11 @@
         updateCall(call);
     }
 
+    @Override
+    public void onStatusHintsChanged(Call call) {
+        updateCall(call);
+    }
+
     void bringToForeground(boolean showDialpad) {
         if (mInCallService != null) {
             try {
@@ -299,8 +304,8 @@
 
         return new InCallCall(callId, state, call.getDisconnectCause(), call.getDisconnectMessage(),
                 call.getCannedSmsResponses(), capabilities, connectTimeMillis, call.getHandle(),
-                call.getGatewayInfo(), call.getAccount(), descriptor, call.getCallVideoProvider(),
-                parentCallId, childCallIds, call.getFeatures());
+                call.getGatewayInfo(), call.getPhoneAccount(), descriptor,
+                call.getCallVideoProvider(), parentCallId, childCallIds, call.getFeatures(),
+                call.getStatusHints());
     }
-
 }
diff --git a/src/com/android/telecomm/NewOutgoingCallIntentBroadcaster.java b/src/com/android/telecomm/NewOutgoingCallIntentBroadcaster.java
index 770b75d..c75e184 100644
--- a/src/com/android/telecomm/NewOutgoingCallIntentBroadcaster.java
+++ b/src/com/android/telecomm/NewOutgoingCallIntentBroadcaster.java
@@ -26,6 +26,7 @@
 import android.telecomm.GatewayInfo;
 import android.telecomm.PhoneAccount;
 import android.telecomm.TelecommConstants;
+import android.telecomm.VideoCallProfile;
 import android.telephony.PhoneNumberUtils;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
@@ -123,7 +124,9 @@
             mCallsManager.placeOutgoingCall(resultHandleUri, mContactInfo, gatewayInfo,
                     account,
                     mIntent.getBooleanExtra(TelecommConstants.EXTRA_START_CALL_WITH_SPEAKERPHONE,
-                            false));
+                            false),
+                    mIntent.getIntExtra(TelecommConstants.EXTRA_START_CALL_WITH_VIDEO_STATE,
+                            VideoCallProfile.VIDEO_STATE_AUDIO_ONLY));
         }
     }
 
@@ -192,7 +195,9 @@
             mCallsManager.placeOutgoingCall(
                     Uri.fromParts(scheme, handle, null), mContactInfo, null, null,
                     mIntent.getBooleanExtra(TelecommConstants.EXTRA_START_CALL_WITH_SPEAKERPHONE,
-                            false));
+                            false),
+                    mIntent.getIntExtra(TelecommConstants.EXTRA_START_CALL_WITH_VIDEO_STATE,
+                            VideoCallProfile.VIDEO_STATE_AUDIO_ONLY));
 
             // Don't return but instead continue and send the ACTION_NEW_OUTGOING_CALL broadcast
             // so that third parties can still inspect (but not intercept) the outgoing call. When
diff --git a/tests/src/com/android/telecomm/testapps/TestConnectionService.java b/tests/src/com/android/telecomm/testapps/TestConnectionService.java
index 34aa22b..2527cfd 100644
--- a/tests/src/com/android/telecomm/testapps/TestConnectionService.java
+++ b/tests/src/com/android/telecomm/testapps/TestConnectionService.java
@@ -25,10 +25,11 @@
 import android.telecomm.Connection;
 import android.telecomm.ConnectionRequest;
 import android.telecomm.ConnectionService;
+import android.telecomm.PhoneAccount;
 import android.telecomm.RemoteConnection;
 import android.telecomm.Response;
 import android.telecomm.SimpleResponse;
-import android.telecomm.PhoneAccount;
+import android.telecomm.StatusHints;
 import android.telephony.DisconnectCause;
 import android.text.TextUtils;
 import android.util.Log;
@@ -79,6 +80,16 @@
             }
 
             @Override
+            public void onSetAudioModeIsVoip(RemoteConnection connection, boolean isVoip) {
+                setAudioModeIsVoip(isVoip);
+            }
+
+            @Override
+            public void onSetStatusHints(RemoteConnection connection, StatusHints statusHints) {
+                setStatusHints(statusHints);
+            }
+
+            @Override
             public void onDestroyed(RemoteConnection connection) {
                 setDestroyed();
             }
@@ -241,7 +252,8 @@
                         mAccountIterator.next(),
                         mOriginalRequest.getCallId(),
                         mOriginalRequest.getHandle(),
-                        null);
+                        null,
+                        mOriginalRequest.getVideoState());
                 createRemoteOutgoingConnection(connectionRequest, this);
             } else {
                 mCallback.onFailure(mOriginalRequest, 0, null);
@@ -324,7 +336,7 @@
         final ConnectionRequest request = new ConnectionRequest(
                 originalRequest.getCallId(),
                 Uri.fromParts(handle.getScheme(), handle.getSchemeSpecificPart() + "..", ""),
-                originalRequest.getExtras());
+                originalRequest.getExtras(), originalRequest.getVideoState());
 
         // If the number starts with 555, then we handle it ourselves. If not, then we
         // use a remote connection service.
@@ -364,7 +376,8 @@
         TestConnection connection = new TestConnection(null, Connection.State.DIALING);
         mCalls.add(connection);
         callback.onResult(
-                new ConnectionRequest(request.getCallId(), handle, request.getExtras()),
+                new ConnectionRequest(request.getCallId(), handle, request.getExtras(),
+                        request.getVideoState()),
                 connection);
     }
 }