1 /**
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.telephony.imsmedia;
18 
19 import android.os.Handler;
20 import android.os.Looper;
21 import android.os.Message;
22 import android.os.RemoteException;
23 import android.support.annotation.VisibleForTesting;
24 import android.telephony.imsmedia.IImsTextSession;
25 import android.telephony.imsmedia.IImsTextSessionCallback;
26 import android.telephony.imsmedia.ImsMediaSession;
27 import android.telephony.imsmedia.MediaQualityThreshold;
28 import android.telephony.imsmedia.RtpConfig;
29 import android.telephony.imsmedia.TextConfig;
30 
31 import androidx.annotation.NonNull;
32 import androidx.annotation.Nullable;
33 
34 import com.android.telephony.imsmedia.Utils.OpenSessionParams;
35 import com.android.telephony.imsmedia.util.Log;
36 
37 /**
38  * Text session binder implementation which handles all text session APIs from the text service.
39  */
40 public final class TextSession extends IImsTextSession.Stub implements IMediaSession {
41     private static final String TAG = "TextSession";
42 
43     public static final int CMD_OPEN_SESSION = 101;
44     public static final int CMD_CLOSE_SESSION = 102;
45     public static final int CMD_MODIFY_SESSION = 103;
46     public static final int CMD_SET_MEDIA_QUALITY_THRESHOLD = 104;
47     public static final int CMD_SEND_RTT = 105;
48 
49     public static final int EVENT_OPEN_SESSION_SUCCESS = 201;
50     public static final int EVENT_OPEN_SESSION_FAILURE = 202;
51     public static final int EVENT_MODIFY_SESSION_RESPONSE = 203;
52     public static final int EVENT_MEDIA_INACTIVITY_IND = 204;
53     public static final int EVENT_RTT_RECEIVED = 205;
54     public static final int EVENT_SESSION_CLOSED = 206;
55 
56     private int mSessionId;
57     private IImsTextSessionCallback mCallback;
58     private TextSessionHandler mHandler;
59     private TextService mTextService;
60     private TextListener mTextListener;
61     private TextLocalSession mLocalSession;
62 
TextSession(final int sessionId, final IImsTextSessionCallback callback)63     TextSession(final int sessionId, final IImsTextSessionCallback callback) {
64         mSessionId = sessionId;
65         mCallback = callback;
66         mHandler = new TextSessionHandler(Looper.getMainLooper());
67         Log.d(TAG, "Initialize local text service");
68         mTextService = new TextService();
69         mTextListener = new TextListener(mHandler);
70         mTextService.setListener(mTextListener);
71         mTextListener.setNativeObject(mTextService.getNativeObject());
72     }
73 
74     @VisibleForTesting
TextSession(final int sessionId, final @NonNull IImsTextSessionCallback callback, final @Nullable TextService textService, final @Nullable TextLocalSession localSession, Looper looper)75     TextSession(final int sessionId,
76             final @NonNull IImsTextSessionCallback callback,
77             final @Nullable TextService textService,
78             final @Nullable TextLocalSession localSession, Looper looper) {
79         mSessionId = sessionId;
80         mCallback = callback;
81         mHandler = new TextSessionHandler(looper);
82         mTextService = textService;
83         mLocalSession = localSession;
84         mTextListener = new TextListener(mHandler);
85     }
86 
87     @VisibleForTesting
getTextSessionHandler()88     TextSessionHandler getTextSessionHandler() {
89         return mHandler;
90     }
91 
92     @VisibleForTesting
getTextListener()93     TextListener getTextListener() {
94         return mTextListener;
95     }
96 
97     @Override
openSession(OpenSessionParams sessionParams)98     public void openSession(OpenSessionParams sessionParams) {
99         Utils.sendMessage(mHandler, CMD_OPEN_SESSION, sessionParams);
100         RtpConfig rtpConfig = sessionParams.getRtpConfig();
101         if (rtpConfig != null) {
102             WakeLockManager.getInstance().manageWakeLockOnMediaDirectionUpdate(
103                     mSessionId, rtpConfig.getMediaDirection());
104         }
105     }
106 
107     @Override
closeSession()108     public void closeSession() {
109         Utils.sendMessage(mHandler, CMD_CLOSE_SESSION);
110         WakeLockManager.getInstance().manageWakeLockOnMediaDirectionUpdate(
111                 mSessionId, RtpConfig.MEDIA_DIRECTION_NO_FLOW);
112     }
113 
114     @Override
getSessionId()115     public int getSessionId() {
116         return mSessionId;
117     }
118 
119     @Override
modifySession(TextConfig config)120     public void modifySession(TextConfig config) {
121         Log.d(TAG, "modifySession: " + Log.hidePii(String.valueOf(config)));
122         Utils.sendMessage(mHandler, CMD_MODIFY_SESSION, config);
123         WakeLockManager.getInstance().manageWakeLockOnMediaDirectionUpdate(
124                 mSessionId, config.getMediaDirection());
125     }
126 
127     @Override
setMediaQualityThreshold(MediaQualityThreshold threshold)128     public void setMediaQualityThreshold(MediaQualityThreshold threshold) {
129         Log.d(TAG, "setMediaQualityThreshold: " + Log.hidePii(String.valueOf(threshold)));
130         Utils.sendMessage(mHandler, CMD_SET_MEDIA_QUALITY_THRESHOLD, threshold);
131     }
132 
133     @Override
sendRtt(String text)134     public void sendRtt(String text) {
135         Log.dc(TAG, "sendRtt: ");
136         Utils.sendMessage(mHandler, CMD_SEND_RTT, text);
137     }
138 
139     @Override
onOpenSessionSuccess(Object session)140     public void onOpenSessionSuccess(Object session) {
141         Utils.sendMessage(mHandler, EVENT_OPEN_SESSION_SUCCESS, session);
142     }
143 
144     @Override
onOpenSessionFailure(int error)145     public void onOpenSessionFailure(int error) {
146         Utils.sendMessage(mHandler, EVENT_OPEN_SESSION_FAILURE, error);
147     }
148 
149     @Override
onSessionClosed()150     public void onSessionClosed() {
151         Utils.sendMessage(mHandler, EVENT_SESSION_CLOSED);
152     }
153 
154     /**
155      * Text session message mHandler
156      */
157     class TextSessionHandler extends Handler {
TextSessionHandler(Looper looper)158         TextSessionHandler(Looper looper) {
159             super(looper);
160         }
161 
162         @Override
handleMessage(Message msg)163         public void handleMessage(Message msg) {
164             Log.dc(TAG, "handleMessage() -" + TextSessionHandler.this + ", " + msg.what);
165             switch (msg.what) {
166                 case CMD_OPEN_SESSION:
167                     handleOpenSession((OpenSessionParams) msg.obj);
168                     break;
169                 case CMD_CLOSE_SESSION:
170                     handleCloseSession();
171                     break;
172                 case CMD_MODIFY_SESSION:
173                     handleModifySession((TextConfig) msg.obj);
174                     break;
175                 case CMD_SET_MEDIA_QUALITY_THRESHOLD:
176                     handleSetMediaQualityThreshold((MediaQualityThreshold) msg.obj);
177                     break;
178                 case CMD_SEND_RTT:
179                     handleSendRtt((String) msg.obj);
180                     break;
181                 case EVENT_OPEN_SESSION_SUCCESS:
182                     handleOpenSuccess(msg.obj);
183                     break;
184                 case EVENT_OPEN_SESSION_FAILURE:
185                     handleOpenFailure((int) msg.obj);
186                     break;
187                 case EVENT_SESSION_CLOSED:
188                     handleSessionClosed();
189                     break;
190                 case EVENT_MODIFY_SESSION_RESPONSE:
191                     handleModifySessionRespose((TextConfig) msg.obj, msg.arg1);
192                     break;
193                 case EVENT_MEDIA_INACTIVITY_IND:
194                     handleNotifyMediaInactivityInd(msg.arg1);
195                     break;
196                 case EVENT_RTT_RECEIVED:
197                     handleRttReceived((String) msg.obj);
198                     break;
199                 default:
200             }
201         }
202     }
203 
handleOpenSession(OpenSessionParams sessionParams)204     private void handleOpenSession(OpenSessionParams sessionParams) {
205         mTextListener.setMediaCallback(sessionParams.getCallback());
206         Log.d(TAG, "handleOpenSession");
207         int result = mTextService.openSession(mSessionId, sessionParams);
208         if (result != ImsMediaSession.RESULT_SUCCESS) {
209             handleOpenFailure(result);
210         }
211     }
212 
handleCloseSession()213     private void handleCloseSession() {
214         mTextService.closeSession(mSessionId);
215     }
216 
handleModifySession(TextConfig config)217     private void handleModifySession(TextConfig config) {
218         mLocalSession.modifySession(config);
219     }
220 
handleSetMediaQualityThreshold(MediaQualityThreshold threshold)221     private void handleSetMediaQualityThreshold(MediaQualityThreshold threshold) {
222         mLocalSession.setMediaQualityThreshold(threshold);
223     }
224 
handleSendRtt(String text)225     private void handleSendRtt(String text) {
226         mLocalSession.sendRtt(text);
227     }
228 
handleOpenSuccess(Object session)229     private void handleOpenSuccess(Object session) {
230         mLocalSession = (TextLocalSession) session;
231         try {
232             mCallback.onOpenSessionSuccess(this);
233         } catch (RemoteException e) {
234             Log.e(TAG, "Failed to notify openSuccess: " + e);
235         }
236     }
237 
handleOpenFailure(int error)238     private void handleOpenFailure(int error) {
239         try {
240             mCallback.onOpenSessionFailure(error);
241         } catch (RemoteException e) {
242             Log.e(TAG, "Failed to notify openFailure: " + e);
243         }  finally {
244             WakeLockManager.getInstance().manageWakeLockOnMediaDirectionUpdate(
245                     mSessionId, RtpConfig.MEDIA_DIRECTION_NO_FLOW);
246         }
247     }
248 
handleSessionClosed()249     private void handleSessionClosed() {
250         try {
251             mCallback.onSessionClosed();
252         }  catch (RemoteException e) {
253             Log.e(TAG, "Failed to notify SessionClosed: " + e);
254         }
255     }
256 
handleModifySessionRespose(TextConfig config, int error)257     private void handleModifySessionRespose(TextConfig config, int error) {
258         try {
259             if (error != ImsMediaSession.RESULT_SUCCESS) {
260                 Log.e(TAG, "modifySession failed with error: " + error);
261             }
262             mCallback.onModifySessionResponse(config, error);
263         } catch (RemoteException e) {
264             Log.e(TAG, "Failed to notify modifySessionResponse: " + e);
265         }
266     }
267 
handleNotifyMediaInactivityInd(int packetType)268     private void handleNotifyMediaInactivityInd(int packetType) {
269         try {
270             mCallback.notifyMediaInactivity(packetType);
271         } catch (RemoteException e) {
272             Log.e(TAG, "Failed to notify media timeout: " + e);
273         }
274     }
275 
handleRttReceived(String text)276     private void handleRttReceived(String text) {
277         try {
278             mCallback.onRttReceived(text);
279         } catch (RemoteException e) {
280             Log.e(TAG, "Failed to notify rtt received: " + e);
281         }
282     }
283 }
284