186014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn/*
286014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn * Copyright (C) 2015 The Android Open Source Project
386014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn *
486014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn * Licensed under the Apache License, Version 2.0 (the "License");
586014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn * you may not use this file except in compliance with the License.
686014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn * You may obtain a copy of the License at
786014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn *
886014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn *      http://www.apache.org/licenses/LICENSE-2.0
986014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn *
1086014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn * Unless required by applicable law or agreed to in writing, software
1186014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn * distributed under the License is distributed on an "AS IS" BASIS,
1286014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1386014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn * See the License for the specific language governing permissions and
1486014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn * limitations under the License
1586014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn */
1686014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn
1786014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunnpackage com.android.server.telecom;
1886014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn
19a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunnimport android.Manifest;
20a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunnimport android.app.AppOpsManager;
21a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunnimport android.content.Context;
2286014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunnimport android.net.Uri;
23a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunnimport android.os.Binder;
24115c06ee64e209cda99abdc1fbd23fd65aa6da47Tyler Gunnimport android.os.Build;
2586014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunnimport android.os.IBinder;
2686014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunnimport android.os.Looper;
2786014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunnimport android.os.RemoteException;
281bf0e6be00af0ca5731a52f0727c6d9a2f8b6944Tyler Gunnimport android.os.UserHandle;
2986014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunnimport android.telecom.Connection;
3086014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunnimport android.telecom.InCallService;
31a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebingerimport android.telecom.Log;
3286014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunnimport android.telecom.VideoProfile;
33a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunnimport android.text.TextUtils;
3486014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunnimport android.view.Surface;
3586014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn
3686014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunnimport com.android.internal.telecom.IVideoCallback;
3786014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunnimport com.android.internal.telecom.IVideoProvider;
3886014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn
3986014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunnimport java.util.Collections;
4086014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunnimport java.util.Set;
4186014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunnimport java.util.concurrent.ConcurrentHashMap;
4286014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn
43a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunnimport static android.Manifest.permission.CALL_PHONE;
44a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn
4586014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn/**
4686014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn * Proxies video provider messages from {@link InCallService.VideoCall}
4786014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn * implementations to the underlying {@link Connection.VideoProvider} implementation.  Also proxies
4886014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn * callbacks from the {@link Connection.VideoProvider} to {@link InCallService.VideoCall}
4986014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn * implementations.
5086014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn *
5186014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn * Also provides a means for Telecom to send and receive these messages.
5286014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn */
5386014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunnpublic class VideoProviderProxy extends Connection.VideoProvider {
5486014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn
5586014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    /**
5686014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * Listener for Telecom components interested in callbacks from the video provider.
5786014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     */
5886014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    interface Listener {
5986014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        void onSessionModifyRequestReceived(Call call, VideoProfile videoProfile);
6086014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    }
6186014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn
6286014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    /**
6386014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * Set of listeners on this VideoProviderProxy.
6486014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     *
6586014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is
6686014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * load factor before resizing, 1 means we only expect a single thread to
6786014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * access the map so make only a single shard
6886014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     */
6986014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    private final Set<Listener> mListeners = Collections.newSetFromMap(
7086014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            new ConcurrentHashMap<Listener, Boolean>(8, 0.9f, 1));
7186014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn
7286014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    /** The TelecomSystem SyncRoot used for synchronized operations. */
7386014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    private final TelecomSystem.SyncRoot mLock;
7486014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn
7586014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    /**
7686014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * The {@link android.telecom.Connection.VideoProvider} implementation residing with the
7786014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * {@link android.telecom.ConnectionService} which is being wrapped by this
7886014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * {@link VideoProviderProxy}.
7986014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     */
8086014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    private final IVideoProvider mConectionServiceVideoProvider;
8186014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn
8286014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    /**
8386014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * Binder used to bind to the {@link android.telecom.ConnectionService}'s
8486014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * {@link com.android.internal.telecom.IVideoCallback}.
8586014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     */
8686014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    private final VideoCallListenerBinder mVideoCallListenerBinder;
8786014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn
8886014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    /**
8986014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * The Telecom {@link Call} this {@link VideoProviderProxy} is associated with.
9086014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     */
9186014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    private Call mCall;
9286014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn
931bf0e6be00af0ca5731a52f0727c6d9a2f8b6944Tyler Gunn    /**
941bf0e6be00af0ca5731a52f0727c6d9a2f8b6944Tyler Gunn     * Interface providing access to the currently logged in user.
951bf0e6be00af0ca5731a52f0727c6d9a2f8b6944Tyler Gunn     */
961bf0e6be00af0ca5731a52f0727c6d9a2f8b6944Tyler Gunn    private CurrentUserProxy mCurrentUserProxy;
971bf0e6be00af0ca5731a52f0727c6d9a2f8b6944Tyler Gunn
9886014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
9986014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        @Override
10086014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        public void binderDied() {
10186014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            mConectionServiceVideoProvider.asBinder().unlinkToDeath(this, 0);
10286014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        }
10386014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    };
10486014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn
10586014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    /**
10686014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * Creates a new instance of the {@link VideoProviderProxy}, binding it to the passed in
10786014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * {@code videoProvider} residing with the {@link android.telecom.ConnectionService}.
10886014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     *
10986014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     *
11086014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * @param lock
11186014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * @param videoProvider The {@link android.telecom.ConnectionService}'s video provider.
11286014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * @param call The current call.
11386014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * @throws RemoteException Remote exception.
11486014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     */
11586014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    VideoProviderProxy(TelecomSystem.SyncRoot lock,
1161bf0e6be00af0ca5731a52f0727c6d9a2f8b6944Tyler Gunn            IVideoProvider videoProvider, Call call, CurrentUserProxy currentUserProxy)
1171bf0e6be00af0ca5731a52f0727c6d9a2f8b6944Tyler Gunn            throws RemoteException {
11886014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn
11986014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        super(Looper.getMainLooper());
12086014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn
12186014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        mLock = lock;
12286014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn
12386014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        mConectionServiceVideoProvider = videoProvider;
12486014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        mConectionServiceVideoProvider.asBinder().linkToDeath(mDeathRecipient, 0);
12586014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn
12686014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        mVideoCallListenerBinder = new VideoCallListenerBinder();
12786014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        mConectionServiceVideoProvider.addVideoCallback(mVideoCallListenerBinder);
12886014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        mCall = call;
1291bf0e6be00af0ca5731a52f0727c6d9a2f8b6944Tyler Gunn        mCurrentUserProxy = currentUserProxy;
13086014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    }
13186014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn
13286014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    /**
13386014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * IVideoCallback stub implementation.  An instance of this class receives callbacks from the
13486014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * {@code ConnectionService}'s video provider.
13586014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     */
13686014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    private final class VideoCallListenerBinder extends IVideoCallback.Stub {
13786014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        /**
13886014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn         * Proxies a request from the {@link #mConectionServiceVideoProvider} to the
13986014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn         * {@link InCallService} when a session modification request is received.
14086014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn         *
14186014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn         * @param videoProfile The requested video profile.
14286014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn         */
14386014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        @Override
14486014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        public void receiveSessionModifyRequest(VideoProfile videoProfile) {
1453165d50d3fc688d632faecfae9c2f987e537941fBrad Ebinger            try {
1463165d50d3fc688d632faecfae9c2f987e537941fBrad Ebinger                Log.startSession("VPP.rSMR");
1473165d50d3fc688d632faecfae9c2f987e537941fBrad Ebinger                synchronized (mLock) {
1483165d50d3fc688d632faecfae9c2f987e537941fBrad Ebinger                    logFromVideoProvider("receiveSessionModifyRequest: " + videoProfile);
149a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                    Log.addEvent(mCall, LogUtils.Events.RECEIVE_VIDEO_REQUEST,
15070d6f858f10a77277c63aafcaa1f113f647117a6Tyler Gunn                            VideoProfile.videoStateToString(videoProfile.getVideoState()));
15186014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn
1524640c4fc55ca4118351330d68684ca9989661ccdHall Liu                    mCall.getAnalytics().addVideoEvent(
1534640c4fc55ca4118351330d68684ca9989661ccdHall Liu                            Analytics.RECEIVE_REMOTE_SESSION_MODIFY_REQUEST,
1544640c4fc55ca4118351330d68684ca9989661ccdHall Liu                            videoProfile.getVideoState());
15513e8a6938eb5db779ea41f82f00916363ad09aa6Tyler Gunn
15613e8a6938eb5db779ea41f82f00916363ad09aa6Tyler Gunn                    if (!mCall.isVideoCallingSupported() &&
15713e8a6938eb5db779ea41f82f00916363ad09aa6Tyler Gunn                            VideoProfile.isVideo(videoProfile.getVideoState())) {
15813e8a6938eb5db779ea41f82f00916363ad09aa6Tyler Gunn                        // If video calling is not supported by the phone account, and we receive
15913e8a6938eb5db779ea41f82f00916363ad09aa6Tyler Gunn                        // a request to upgrade to video, automatically reject it without informing
16013e8a6938eb5db779ea41f82f00916363ad09aa6Tyler Gunn                        // the InCallService.
16113e8a6938eb5db779ea41f82f00916363ad09aa6Tyler Gunn
162a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                        Log.addEvent(mCall, LogUtils.Events.SEND_VIDEO_RESPONSE, "video not supported");
16313e8a6938eb5db779ea41f82f00916363ad09aa6Tyler Gunn                        VideoProfile responseProfile = new VideoProfile(
16413e8a6938eb5db779ea41f82f00916363ad09aa6Tyler Gunn                                VideoProfile.STATE_AUDIO_ONLY);
16513e8a6938eb5db779ea41f82f00916363ad09aa6Tyler Gunn                        try {
16613e8a6938eb5db779ea41f82f00916363ad09aa6Tyler Gunn                            mConectionServiceVideoProvider.sendSessionModifyResponse(
16713e8a6938eb5db779ea41f82f00916363ad09aa6Tyler Gunn                                    responseProfile);
16813e8a6938eb5db779ea41f82f00916363ad09aa6Tyler Gunn                        } catch (RemoteException e) {
16913e8a6938eb5db779ea41f82f00916363ad09aa6Tyler Gunn                        }
17013e8a6938eb5db779ea41f82f00916363ad09aa6Tyler Gunn
17113e8a6938eb5db779ea41f82f00916363ad09aa6Tyler Gunn                        // Don't want to inform listeners of the request as we've just rejected it.
17213e8a6938eb5db779ea41f82f00916363ad09aa6Tyler Gunn                        return;
17313e8a6938eb5db779ea41f82f00916363ad09aa6Tyler Gunn                    }
17413e8a6938eb5db779ea41f82f00916363ad09aa6Tyler Gunn
1753165d50d3fc688d632faecfae9c2f987e537941fBrad Ebinger                    // Inform other Telecom components of the session modification request.
1763165d50d3fc688d632faecfae9c2f987e537941fBrad Ebinger                    for (Listener listener : mListeners) {
1773165d50d3fc688d632faecfae9c2f987e537941fBrad Ebinger                        listener.onSessionModifyRequestReceived(mCall, videoProfile);
1783165d50d3fc688d632faecfae9c2f987e537941fBrad Ebinger                    }
17986014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn
1803165d50d3fc688d632faecfae9c2f987e537941fBrad Ebinger                    VideoProviderProxy.this.receiveSessionModifyRequest(videoProfile);
1813165d50d3fc688d632faecfae9c2f987e537941fBrad Ebinger                }
1823165d50d3fc688d632faecfae9c2f987e537941fBrad Ebinger            } finally {
1833165d50d3fc688d632faecfae9c2f987e537941fBrad Ebinger                Log.endSession();
18486014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            }
18586014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        }
18686014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn
18786014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        /**
18886014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn         * Proxies a request from the {@link #mConectionServiceVideoProvider} to the
18986014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn         * {@link InCallService} when a session modification response is received.
19086014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn         *
19186014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn         * @param status The status of the response.
19286014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn         * @param requestProfile The requested video profile.
19386014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn         * @param responseProfile The response video profile.
19486014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn         */
19586014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        @Override
19686014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        public void receiveSessionModifyResponse(int status, VideoProfile requestProfile,
19786014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn                VideoProfile responseProfile) {
19810f8cd2c3f51b2fb3dc1d70ceac6bd6127f860d5Brad Ebinger            logFromVideoProvider("receiveSessionModifyResponse: status=" + status +
19910f8cd2c3f51b2fb3dc1d70ceac6bd6127f860d5Brad Ebinger                    " requestProfile=" + requestProfile + " responseProfile=" + responseProfile);
20010f8cd2c3f51b2fb3dc1d70ceac6bd6127f860d5Brad Ebinger            String eventMessage = "Status Code : " + status + " Video State: " +
20110f8cd2c3f51b2fb3dc1d70ceac6bd6127f860d5Brad Ebinger                    (responseProfile != null ? responseProfile.getVideoState() : "null");
202a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger            Log.addEvent(mCall, LogUtils.Events.RECEIVE_VIDEO_RESPONSE, eventMessage);
20386014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            synchronized (mLock) {
20410f8cd2c3f51b2fb3dc1d70ceac6bd6127f860d5Brad Ebinger                if (status == Connection.VideoProvider.SESSION_MODIFY_REQUEST_SUCCESS) {
20510f8cd2c3f51b2fb3dc1d70ceac6bd6127f860d5Brad Ebinger                    mCall.getAnalytics().addVideoEvent(
20610f8cd2c3f51b2fb3dc1d70ceac6bd6127f860d5Brad Ebinger                            Analytics.RECEIVE_REMOTE_SESSION_MODIFY_RESPONSE,
2072f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                            responseProfile == null ?
2082f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                                    VideoProfile.STATE_AUDIO_ONLY :
2092f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                                    responseProfile.getVideoState());
21010f8cd2c3f51b2fb3dc1d70ceac6bd6127f860d5Brad Ebinger                }
21186014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn                VideoProviderProxy.this.receiveSessionModifyResponse(status, requestProfile,
21286014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn                        responseProfile);
21386014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            }
21486014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        }
21586014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn
21686014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        /**
21786014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn         * Proxies a request from the {@link #mConectionServiceVideoProvider} to the
21886014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn         * {@link InCallService} when a call session event occurs.
21986014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn         *
22086014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn         * @param event The call session event.
22186014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn         */
22286014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        @Override
22386014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        public void handleCallSessionEvent(int event) {
22486014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            synchronized (mLock) {
22533e453811b7dc0af47301d1aa22384de3d464da4Tyler Gunn                logFromVideoProvider("handleCallSessionEvent: " +
22633e453811b7dc0af47301d1aa22384de3d464da4Tyler Gunn                        Connection.VideoProvider.sessionEventToString(event));
22786014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn                VideoProviderProxy.this.handleCallSessionEvent(event);
22886014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            }
22986014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        }
23086014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn
23186014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        /**
23286014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn         * Proxies a request from the {@link #mConectionServiceVideoProvider} to the
23386014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn         * {@link InCallService} when the peer dimensions change.
23486014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn         *
23586014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn         * @param width The width of the peer's video.
23686014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn         * @param height The height of the peer's video.
23786014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn         */
23886014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        @Override
23986014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        public void changePeerDimensions(int width, int height) {
24086014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            synchronized (mLock) {
24186014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn                logFromVideoProvider("changePeerDimensions: width=" + width + " height=" +
24286014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn                        height);
24386014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn                VideoProviderProxy.this.changePeerDimensions(width, height);
24486014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            }
24586014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        }
24686014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn
24786014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        /**
24886014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn         * Proxies a request from the {@link #mConectionServiceVideoProvider} to the
24986014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn         * {@link InCallService} when the video quality changes.
25086014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn         *
25186014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn         * @param videoQuality The video quality.
25286014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn         */
25386014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        @Override
25486014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        public void changeVideoQuality(int videoQuality) {
25586014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            synchronized (mLock) {
25686014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn                logFromVideoProvider("changeVideoQuality: " + videoQuality);
25786014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn                VideoProviderProxy.this.changeVideoQuality(videoQuality);
25886014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            }
25986014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        }
26086014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn
26186014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        /**
26286014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn         * Proxies a request from the {@link #mConectionServiceVideoProvider} to the
26386014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn         * {@link InCallService} when the call data usage changes.
26486014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn         *
2657a1f8239f7d22faef49c1f89de522e908e2e43f8Tyler Gunn         * Also tracks the current call data usage on the {@link Call} for use when writing to the
2667a1f8239f7d22faef49c1f89de522e908e2e43f8Tyler Gunn         * call log.
2677a1f8239f7d22faef49c1f89de522e908e2e43f8Tyler Gunn         *
26886014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn         * @param dataUsage The data usage.
26986014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn         */
27086014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        @Override
27186014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        public void changeCallDataUsage(long dataUsage) {
27286014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            synchronized (mLock) {
27386014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn                logFromVideoProvider("changeCallDataUsage: " + dataUsage);
27486014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn                VideoProviderProxy.this.setCallDataUsage(dataUsage);
2757a1f8239f7d22faef49c1f89de522e908e2e43f8Tyler Gunn                mCall.setCallDataUsage(dataUsage);
27686014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            }
27786014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        }
27886014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn
27986014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        /**
28086014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn         * Proxies a request from the {@link #mConectionServiceVideoProvider} to the
28186014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn         * {@link InCallService} when the camera capabilities change.
28286014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn         *
28386014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn         * @param cameraCapabilities The camera capabilities.
28486014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn         */
28586014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        @Override
28686014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        public void changeCameraCapabilities(VideoProfile.CameraCapabilities cameraCapabilities) {
28786014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            synchronized (mLock) {
28886014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn                logFromVideoProvider("changeCameraCapabilities: " + cameraCapabilities);
28986014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn                VideoProviderProxy.this.changeCameraCapabilities(cameraCapabilities);
29086014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            }
29186014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        }
29286014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    }
29386014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn
294a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn    @Override
295a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn    public void onSetCamera(String cameraId) {
296a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn        // No-op.  We implement the other prototype of onSetCamera so that we can use the calling
297a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn        // package, uid and pid to verify permission.
298a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn    }
299a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn
30086014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    /**
30186014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * Proxies a request from the {@link InCallService} to the
30286014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * {@link #mConectionServiceVideoProvider} to change the camera.
30386014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     *
30486014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * @param cameraId The id of the camera.
305a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn     * @param callingPackage The package calling in.
306a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn     * @param callingUid The UID of the caller.
307a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn     * @param callingPid The PID of the caller.
308115c06ee64e209cda99abdc1fbd23fd65aa6da47Tyler Gunn     * @param targetSdkVersion The target SDK version of the calling InCallService where the camera
309115c06ee64e209cda99abdc1fbd23fd65aa6da47Tyler Gunn     *      request originated.
31086014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     */
31186014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    @Override
312a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn    public void onSetCamera(String cameraId, String callingPackage, int callingUid,
313115c06ee64e209cda99abdc1fbd23fd65aa6da47Tyler Gunn            int callingPid, int targetSdkVersion) {
31486014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        synchronized (mLock) {
3151bf0e6be00af0ca5731a52f0727c6d9a2f8b6944Tyler Gunn            logFromInCall("setCamera: " + cameraId + " callingPackage=" + callingPackage +
3161bf0e6be00af0ca5731a52f0727c6d9a2f8b6944Tyler Gunn                    "; callingUid=" + callingUid);
317a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn
318a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn            if (!TextUtils.isEmpty(cameraId)) {
319a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn                if (!canUseCamera(mCall.getContext(), callingPackage, callingUid, callingPid)) {
320a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn                    // Calling app is not permitted to use the camera.  Ignore the request and send
321a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn                    // back a call session event indicating the error.
322772fdf6e57e44ced7d969eccedfe8cab2713e0d6Garik Badalyan                    Log.i(this, "onSetCamera: camera permission denied; package=%s, uid=%d, "
323115c06ee64e209cda99abdc1fbd23fd65aa6da47Tyler Gunn                            + "pid=%d, targetSdkVersion=%d",
324115c06ee64e209cda99abdc1fbd23fd65aa6da47Tyler Gunn                            callingPackage, callingUid, callingPid, targetSdkVersion);
325115c06ee64e209cda99abdc1fbd23fd65aa6da47Tyler Gunn
326115c06ee64e209cda99abdc1fbd23fd65aa6da47Tyler Gunn                    // API 26 introduces a new camera permission error we can use here since the
327115c06ee64e209cda99abdc1fbd23fd65aa6da47Tyler Gunn                    // caller supports that API version.
328115c06ee64e209cda99abdc1fbd23fd65aa6da47Tyler Gunn                    if (targetSdkVersion > Build.VERSION_CODES.N_MR1) {
329115c06ee64e209cda99abdc1fbd23fd65aa6da47Tyler Gunn                        VideoProviderProxy.this.handleCallSessionEvent(
330115c06ee64e209cda99abdc1fbd23fd65aa6da47Tyler Gunn                                Connection.VideoProvider.SESSION_EVENT_CAMERA_PERMISSION_ERROR);
331115c06ee64e209cda99abdc1fbd23fd65aa6da47Tyler Gunn                    } else {
332115c06ee64e209cda99abdc1fbd23fd65aa6da47Tyler Gunn                        VideoProviderProxy.this.handleCallSessionEvent(
333115c06ee64e209cda99abdc1fbd23fd65aa6da47Tyler Gunn                                Connection.VideoProvider.SESSION_EVENT_CAMERA_FAILURE);
334115c06ee64e209cda99abdc1fbd23fd65aa6da47Tyler Gunn                    }
335a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn                    return;
336a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn                }
337a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn            }
33886014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            try {
339115c06ee64e209cda99abdc1fbd23fd65aa6da47Tyler Gunn                mConectionServiceVideoProvider.setCamera(cameraId, callingPackage,
340115c06ee64e209cda99abdc1fbd23fd65aa6da47Tyler Gunn                        targetSdkVersion);
34186014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            } catch (RemoteException e) {
342a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn                VideoProviderProxy.this.handleCallSessionEvent(
343a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn                        Connection.VideoProvider.SESSION_EVENT_CAMERA_FAILURE);
34486014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            }
34586014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        }
34686014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    }
34786014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn
34886014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    /**
34986014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * Proxies a request from the {@link InCallService} to the
35086014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * {@link #mConectionServiceVideoProvider} to set the preview surface.
35186014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     *
35286014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * @param surface The surface.
35386014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     */
35486014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    @Override
35586014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    public void onSetPreviewSurface(Surface surface) {
35686014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        synchronized (mLock) {
35786014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            logFromInCall("setPreviewSurface");
35886014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            try {
35986014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn                mConectionServiceVideoProvider.setPreviewSurface(surface);
36086014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            } catch (RemoteException e) {
36186014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            }
36286014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        }
36386014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    }
36486014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn
36586014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    /**
36686014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * Proxies a request from the {@link InCallService} to the
36786014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * {@link #mConectionServiceVideoProvider} to change the display surface.
36886014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     *
36986014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * @param surface The surface.
37086014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     */
37186014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    @Override
37286014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    public void onSetDisplaySurface(Surface surface) {
37386014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        synchronized (mLock) {
37486014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            logFromInCall("setDisplaySurface");
37586014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            try {
37686014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn                mConectionServiceVideoProvider.setDisplaySurface(surface);
37786014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            } catch (RemoteException e) {
37886014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            }
37986014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        }
38086014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    }
38186014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn
38286014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    /**
38386014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * Proxies a request from the {@link InCallService} to the
38486014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * {@link #mConectionServiceVideoProvider} to change the device orientation.
38586014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     *
38686014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * @param rotation The device orientation, in degrees.
38786014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     */
38886014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    @Override
38986014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    public void onSetDeviceOrientation(int rotation) {
39086014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        synchronized (mLock) {
39186014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            logFromInCall("setDeviceOrientation: " + rotation);
39286014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            try {
39386014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn                mConectionServiceVideoProvider.setDeviceOrientation(rotation);
39486014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            } catch (RemoteException e) {
39586014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            }
39686014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        }
39786014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    }
39886014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn
39986014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    /**
40086014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * Proxies a request from the {@link InCallService} to the
40186014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * {@link #mConectionServiceVideoProvider} to change the camera zoom ratio.
40286014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     *
40386014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * @param value The camera zoom ratio.
40486014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     */
40586014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    @Override
40686014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    public void onSetZoom(float value) {
40786014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        synchronized (mLock) {
40886014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            logFromInCall("setZoom: " + value);
40986014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            try {
41086014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn                mConectionServiceVideoProvider.setZoom(value);
41186014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            } catch (RemoteException e) {
41286014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            }
41386014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        }
41486014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    }
41586014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn
41686014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    /**
41786014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * Proxies a request from the {@link InCallService} to the
41886014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * {@link #mConectionServiceVideoProvider} to provide a response to a session modification
41986014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * request.
42086014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     *
42186014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * @param fromProfile The video properties prior to the request.
42286014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * @param toProfile The video properties with the requested changes made.
42386014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     */
42486014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    @Override
42586014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    public void onSendSessionModifyRequest(VideoProfile fromProfile, VideoProfile toProfile) {
42686014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        synchronized (mLock) {
42786014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            logFromInCall("sendSessionModifyRequest: from=" + fromProfile + " to=" + toProfile);
428a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger            Log.addEvent(mCall, LogUtils.Events.SEND_VIDEO_REQUEST,
42970d6f858f10a77277c63aafcaa1f113f647117a6Tyler Gunn                    VideoProfile.videoStateToString(toProfile.getVideoState()));
4304640c4fc55ca4118351330d68684ca9989661ccdHall Liu            mCall.getAnalytics().addVideoEvent(
4314640c4fc55ca4118351330d68684ca9989661ccdHall Liu                    Analytics.SEND_LOCAL_SESSION_MODIFY_REQUEST,
4324640c4fc55ca4118351330d68684ca9989661ccdHall Liu                    toProfile.getVideoState());
43386014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            try {
43486014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn                mConectionServiceVideoProvider.sendSessionModifyRequest(fromProfile, toProfile);
43586014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            } catch (RemoteException e) {
43686014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            }
43786014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        }
43886014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    }
43986014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn
44086014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    /**
44186014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * Proxies a request from the {@link InCallService} to the
44286014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * {@link #mConectionServiceVideoProvider} to send a session modification request.
44386014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     *
44486014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * @param responseProfile The response connection video properties.
44586014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     */
44686014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    @Override
44786014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    public void onSendSessionModifyResponse(VideoProfile responseProfile) {
44886014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        synchronized (mLock) {
44986014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            logFromInCall("sendSessionModifyResponse: " + responseProfile);
450a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger            Log.addEvent(mCall, LogUtils.Events.SEND_VIDEO_RESPONSE,
45170d6f858f10a77277c63aafcaa1f113f647117a6Tyler Gunn                    VideoProfile.videoStateToString(responseProfile.getVideoState()));
4524640c4fc55ca4118351330d68684ca9989661ccdHall Liu            mCall.getAnalytics().addVideoEvent(
4534640c4fc55ca4118351330d68684ca9989661ccdHall Liu                    Analytics.SEND_LOCAL_SESSION_MODIFY_RESPONSE,
4544640c4fc55ca4118351330d68684ca9989661ccdHall Liu                    responseProfile.getVideoState());
45586014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            try {
45686014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn                mConectionServiceVideoProvider.sendSessionModifyResponse(responseProfile);
45786014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            } catch (RemoteException e) {
45886014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            }
45986014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        }
46086014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    }
46186014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn
46286014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    /**
46386014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * Proxies a request from the {@link InCallService} to the
46486014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * {@link #mConectionServiceVideoProvider} to request the camera capabilities.
46586014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     */
46686014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    @Override
46786014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    public void onRequestCameraCapabilities() {
46886014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        synchronized (mLock) {
46986014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            logFromInCall("requestCameraCapabilities");
47086014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            try {
47186014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn                mConectionServiceVideoProvider.requestCameraCapabilities();
47286014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            } catch (RemoteException e) {
47386014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            }
47486014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        }
47586014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    }
47686014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn
47786014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    /**
47886014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * Proxies a request from the {@link InCallService} to the
47986014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * {@link #mConectionServiceVideoProvider} to request the connection data usage.
48086014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     */
48186014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    @Override
48286014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    public void onRequestConnectionDataUsage() {
48386014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        synchronized (mLock) {
48486014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            logFromInCall("requestCallDataUsage");
48586014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            try {
48686014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn                mConectionServiceVideoProvider.requestCallDataUsage();
48786014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            } catch (RemoteException e) {
48886014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            }
48986014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        }
49086014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    }
49186014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn
49286014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    /**
49386014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * Proxies a request from the {@link InCallService} to the
49486014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * {@link #mConectionServiceVideoProvider} to set the pause image.
49586014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     *
49686014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * @param uri URI of image to display.
49786014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     */
49886014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    @Override
49986014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    public void onSetPauseImage(Uri uri) {
50086014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        synchronized (mLock) {
50186014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            logFromInCall("setPauseImage: " + uri);
50286014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            try {
50386014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn                mConectionServiceVideoProvider.setPauseImage(uri);
50486014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            } catch (RemoteException e) {
50586014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            }
50686014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        }
50786014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    }
50886014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn
50986014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    /**
51086014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * Add a listener to this {@link VideoProviderProxy}.
51186014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     *
51286014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * @param listener The listener.
51386014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     */
51486014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    public void addListener(Listener listener) {
51586014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        mListeners.add(listener);
51686014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    }
51786014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn
51886014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    /**
51986014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * Remove a listener from this {@link VideoProviderProxy}.
52086014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     *
52186014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * @param listener The listener.
52286014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     */
52386014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    public void removeListener(Listener listener) {
52486014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        if (listener != null) {
52586014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn            mListeners.remove(listener);
52686014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn        }
52786014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    }
52886014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn
52986014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    /**
53086014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * Logs a message originating from the {@link InCallService}.
53186014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     *
53286014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * @param toLog The message to log.
53386014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     */
53486014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    private void logFromInCall(String toLog) {
53533e453811b7dc0af47301d1aa22384de3d464da4Tyler Gunn        Log.i(this, "IC->VP (callId=" + (mCall == null ? "?" : mCall.getId()) + "): " + toLog);
53686014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    }
53786014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn
53886014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    /**
53986014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * Logs a message originating from the {@link android.telecom.ConnectionService}'s
54086014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * {@link Connection.VideoProvider}.
54186014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     *
54286014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     * @param toLog The message to log.
54386014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn     */
54486014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    private void logFromVideoProvider(String toLog) {
54533e453811b7dc0af47301d1aa22384de3d464da4Tyler Gunn        Log.i(this, "VP->IC (callId=" + (mCall == null ? "?" : mCall.getId()) + "): " + toLog);
54686014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    }
547a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn
548a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn    /**
549a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn     * Determines if the caller has permission to use the camera.
550a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn     *
551a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn     * @param context The context.
552a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn     * @param callingPackage The package name of the caller (i.e. Dialer).
553a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn     * @param callingUid The UID of the caller.
5541bf0e6be00af0ca5731a52f0727c6d9a2f8b6944Tyler Gunn     * @param callingPid The PID of the caller.
555a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn     * @return {@code true} if the calling uid and package can use the camera, {@code false}
556a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn     *      otherwise.
557a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn     */
558a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn    private boolean canUseCamera(Context context, String callingPackage, int callingUid,
559a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn            int callingPid) {
5601bf0e6be00af0ca5731a52f0727c6d9a2f8b6944Tyler Gunn
5611bf0e6be00af0ca5731a52f0727c6d9a2f8b6944Tyler Gunn        UserHandle callingUser = UserHandle.getUserHandleForUid(callingUid);
5621bf0e6be00af0ca5731a52f0727c6d9a2f8b6944Tyler Gunn        UserHandle currentUserHandle = mCurrentUserProxy.getCurrentUserHandle();
5631bf0e6be00af0ca5731a52f0727c6d9a2f8b6944Tyler Gunn        if (currentUserHandle != null && !currentUserHandle.equals(callingUser)) {
5641bf0e6be00af0ca5731a52f0727c6d9a2f8b6944Tyler Gunn            Log.w(this, "canUseCamera attempt to user camera by background user.");
5651bf0e6be00af0ca5731a52f0727c6d9a2f8b6944Tyler Gunn            return false;
5661bf0e6be00af0ca5731a52f0727c6d9a2f8b6944Tyler Gunn        }
5671bf0e6be00af0ca5731a52f0727c6d9a2f8b6944Tyler Gunn
568a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn        try {
569a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn            context.enforcePermission(Manifest.permission.CAMERA, callingPid, callingUid,
570a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn                    "Camera permission required.");
571a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn        } catch (SecurityException se) {
572a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn            return false;
573a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn        }
574a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn
575a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn        AppOpsManager appOpsManager = (AppOpsManager) context.getSystemService(
576a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn                Context.APP_OPS_SERVICE);
577a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn
578a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn        try {
579a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn            // Some apps that have the permission can be restricted via app ops.
580a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn            return appOpsManager != null && appOpsManager.noteOp(AppOpsManager.OP_CAMERA,
581a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn                    callingUid, callingPackage) == AppOpsManager.MODE_ALLOWED;
582a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn        } catch (SecurityException se) {
5831bf0e6be00af0ca5731a52f0727c6d9a2f8b6944Tyler Gunn            Log.w(this, "canUseCamera got appOpps Exception " + se.toString());
584a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn            return false;
585a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn        }
586a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn    }
587a0a43d51041c9efbe04f7c65236c9e90c3e79346Tyler Gunn
58886014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn}
589