1 /* 2 * Copyright (C) 2023 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.phone.testapps.satellitetestapp; 18 19 import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE; 20 import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED; 21 import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_NONE; 22 import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_SUCCESS; 23 import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING; 24 import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING; 25 import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED; 26 import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS; 27 28 import android.app.Activity; 29 import android.content.Intent; 30 import android.content.SharedPreferences; 31 import android.os.Bundle; 32 import android.telephony.satellite.EnableRequestAttributes; 33 import android.telephony.satellite.PointingInfo; 34 import android.telephony.satellite.SatelliteDatagram; 35 import android.telephony.satellite.SatelliteDatagramCallback; 36 import android.telephony.satellite.SatelliteManager; 37 import android.telephony.satellite.SatelliteModemStateCallback; 38 import android.telephony.satellite.SatelliteTransmissionUpdateCallback; 39 import android.telephony.satellite.stub.SatelliteResult; 40 import android.util.Log; 41 import android.view.View; 42 import android.view.View.OnClickListener; 43 import android.widget.TextView; 44 45 import java.util.LinkedList; 46 import java.util.concurrent.LinkedBlockingQueue; 47 import java.util.concurrent.TimeUnit; 48 import java.util.function.Consumer; 49 50 /** 51 * Activity related to Datagram APIs. 52 */ 53 public class Datagram extends Activity { 54 55 private static final String TAG = "Datagram"; 56 private static final int MAX_NUMBER_OF_STORED_STATES = 3; 57 private int mTransferState; 58 private int mModemState; 59 LinkedList<Integer> mModemStateQueue = new LinkedList<>(); 60 LinkedList<Integer> mSendQueue = new LinkedList<>(); 61 LinkedList<Integer> mReceiveQueue = new LinkedList<>(); 62 63 private SatelliteManager mSatelliteManager; 64 private SatelliteDatagramCallbackTestApp mDatagramCallback; 65 private SatelliteModemStateCallbackTestApp mStateCallback; 66 private SatelliteTransmissionUpdateCallbackTestApp mCallback; 67 private android.telephony.satellite.stub.SatelliteDatagram mReceivedDatagram; 68 69 private String mShowSatelliteModemStateTransition; 70 private String mShowDatagramSendStateTransition; 71 private String mShowDatagramReceiveStateTransition; 72 private static final long TIMEOUT = 3000; 73 74 @Override onCreate(Bundle savedInstanceState)75 public void onCreate(Bundle savedInstanceState) { 76 super.onCreate(savedInstanceState); 77 mSatelliteManager = getSystemService(SatelliteManager.class); 78 mDatagramCallback = new SatelliteDatagramCallbackTestApp(); 79 mStateCallback = new SatelliteModemStateCallbackTestApp(); 80 mCallback = new SatelliteTransmissionUpdateCallbackTestApp(); 81 82 mReceivedDatagram = new android.telephony.satellite.stub.SatelliteDatagram(); 83 84 setContentView(R.layout.activity_Datagram); 85 findViewById(R.id.startSatelliteTransmissionUpdates) 86 .setOnClickListener(this::startTransmissionUpdatesApp); 87 findViewById(R.id.stopSatelliteTransmissionUpdates) 88 .setOnClickListener(this::stopTransmissionUpdatesApp); 89 findViewById(R.id.pollPendingSatelliteDatagrams) 90 .setOnClickListener(this::pollPendingDatagramsApp); 91 findViewById(R.id.sendSatelliteDatagram) 92 .setOnClickListener(this::sendDatagramApp); 93 findViewById(R.id.registerForSatelliteDatagram) 94 .setOnClickListener(this::registerForIncomingDatagramApp); 95 findViewById(R.id.unregisterForSatelliteDatagram) 96 .setOnClickListener(this::unregisterForIncomingDatagramApp); 97 findViewById(R.id.showDatagramSendStateTransition) 98 .setOnClickListener(this::showDatagramSendStateTransitionApp); 99 findViewById(R.id.showDatagramReceiveStateTransition) 100 .setOnClickListener(this::showDatagramReceiveStateTransitionApp); 101 findViewById(R.id.registerForSatelliteModemStateChanged) 102 .setOnClickListener(this::registerForModemStateChangedApp); 103 findViewById(R.id.unregisterForSatelliteModemStateChanged) 104 .setOnClickListener(this::unregisterForModemStateChangedApp); 105 findViewById(R.id.showSatelliteModemStateTransition) 106 .setOnClickListener(this::showSatelliteModemStateTransitionApp); 107 108 findViewById(R.id.Back).setOnClickListener(new OnClickListener() { 109 @Override 110 public void onClick(View view) { 111 startActivity(new Intent(Datagram.this, SatelliteTestApp.class)); 112 } 113 }); 114 } 115 116 protected class SatelliteDatagramCallbackTestApp implements SatelliteDatagramCallback { 117 @Override onSatelliteDatagramReceived(long datagramId, SatelliteDatagram datagram, int pendingCount, Consumer<Void> callback)118 public void onSatelliteDatagramReceived(long datagramId, SatelliteDatagram datagram, 119 int pendingCount, Consumer<Void> callback) { 120 Log.d(TAG, "onSatelliteDatagramReceived in TestApp: datagramId =" + datagramId 121 + ", datagram =" + datagram + ", pendingCount=" + pendingCount); 122 } 123 } 124 125 protected class SatelliteModemStateCallbackTestApp implements SatelliteModemStateCallback { 126 @Override onSatelliteModemStateChanged(int state)127 public void onSatelliteModemStateChanged(int state) { 128 mModemState = state; 129 mModemStateQueue.addLast(state); 130 if (mModemStateQueue.size() > MAX_NUMBER_OF_STORED_STATES) { 131 mModemStateQueue.removeFirst(); 132 } 133 mShowSatelliteModemStateTransition = getSatelliteModemStateTransition(mModemStateQueue); 134 Log.d(TAG, "onSatelliteModemStateChanged in TestApp: state=" + mModemState); 135 } 136 } 137 protected class SatelliteTransmissionUpdateCallbackTestApp implements 138 SatelliteTransmissionUpdateCallback { 139 @Override onSatellitePositionChanged(PointingInfo pointingInfo)140 public void onSatellitePositionChanged(PointingInfo pointingInfo) { 141 Log.d(TAG, "onSatellitePositionChanged in TestApp: pointingInfo =" + pointingInfo); 142 } 143 144 @Override onSendDatagramStateChanged(int state, int sendPendingCount, int errorCode)145 public void onSendDatagramStateChanged(int state, int sendPendingCount, int errorCode) { 146 mTransferState = state; 147 mSendQueue.addLast(state); 148 if (mSendQueue.size() > MAX_NUMBER_OF_STORED_STATES) { 149 mSendQueue.removeFirst(); 150 } 151 mShowDatagramSendStateTransition = getTransferStateTransition(mSendQueue); 152 Log.d(TAG, "onSendDatagramStateChanged in TestApp: state =" + mTransferState 153 + ", sendPendingCount =" + sendPendingCount + ", errorCode=" + errorCode); 154 } 155 156 @Override onSendDatagramStateChanged( int datagramType, int state, int sendPendingCount, int errorCode)157 public void onSendDatagramStateChanged( 158 int datagramType, int state, int sendPendingCount, int errorCode) { 159 Log.d(TAG, "onSendDatagramStateChanged in TestApp: datagramType = " + datagramType 160 + ", state =" + mTransferState + ", sendPendingCount =" + sendPendingCount 161 + ", errorCode=" + errorCode); 162 } 163 164 @Override onReceiveDatagramStateChanged( int state, int receivePendingCount, int errorCode)165 public void onReceiveDatagramStateChanged( 166 int state, int receivePendingCount, int errorCode) { 167 mTransferState = state; 168 mReceiveQueue.addLast(state); 169 if (mReceiveQueue.size() > MAX_NUMBER_OF_STORED_STATES) { 170 mReceiveQueue.removeFirst(); 171 } 172 mShowDatagramReceiveStateTransition = getTransferStateTransition(mReceiveQueue); 173 Log.d(TAG, "onReceiveDatagramStateChanged in TestApp: state=" + mTransferState 174 + ", receivePendingCount=" + receivePendingCount + ", errorCode=" + errorCode); 175 } 176 } 177 startTransmissionUpdatesApp(View view)178 private void startTransmissionUpdatesApp(View view) { 179 TextView textView = findViewById(R.id.text_id); 180 LinkedBlockingQueue<Integer> error = new LinkedBlockingQueue<>(1); 181 mSatelliteManager.requestEnabled( 182 new EnableRequestAttributes.Builder(true).setDemoMode(true).build(), 183 Runnable::run, error::offer); 184 TextView showErrorStatusTextView = findViewById(R.id.showErrorStatus); 185 try { 186 Integer value = error.poll(TIMEOUT, TimeUnit.MILLISECONDS); 187 if (value == null) { 188 showErrorStatusTextView.setText("Timed out to enable the satellite"); 189 return; 190 } else if (value != SatelliteResult.SATELLITE_RESULT_SUCCESS) { 191 showErrorStatusTextView.setText("Failed to enable satellite, error = " 192 + SatelliteErrorUtils.mapError(value)); 193 return; 194 } 195 } catch (InterruptedException e) { 196 showErrorStatusTextView.setText("Enable SatelliteService exception caught = " + e); 197 return; 198 } 199 error.clear(); 200 mSatelliteManager.startTransmissionUpdates(Runnable::run, error::offer, mCallback); 201 try { 202 Integer value = error.poll(TIMEOUT, TimeUnit.MILLISECONDS); 203 if (value == null) { 204 textView.setText("Timed out to startSatelliteTransmissionUpdates"); 205 } else if (value != SatelliteResult.SATELLITE_RESULT_SUCCESS) { 206 textView.setText("Failed to startSatelliteTransmissionUpdates with error = " 207 + SatelliteErrorUtils.mapError(value)); 208 } else { 209 textView.setText("startSatelliteTransmissionUpdates is successful"); 210 } 211 } catch (InterruptedException e) { 212 textView.setText("startSatelliteTransmissionUpdates exception caught =" + e); 213 } 214 } 215 stopTransmissionUpdatesApp(View view)216 private void stopTransmissionUpdatesApp(View view) { 217 TextView textView = findViewById(R.id.text_id); 218 LinkedBlockingQueue<Integer> error = new LinkedBlockingQueue<>(1); 219 mSatelliteManager.stopTransmissionUpdates(mCallback, Runnable::run, error::offer); 220 try { 221 Integer value = error.poll(TIMEOUT, TimeUnit.MILLISECONDS); 222 if (value == null) { 223 textView.setText("Timed out to stopSatelliteTransmissionUpdates"); 224 } else if (value != SatelliteResult.SATELLITE_RESULT_SUCCESS) { 225 textView.setText("Failed to stopSatelliteTransmissionUpdates with error = " 226 + SatelliteErrorUtils.mapError(value)); 227 } else { 228 textView.setText("stopSatelliteTransmissionUpdates is successful"); 229 } 230 } catch (InterruptedException e) { 231 textView.setText("stopSatelliteTransmissionUpdates exception caught =" + e); 232 } 233 } pollPendingDatagramsApp(View view)234 private void pollPendingDatagramsApp(View view) { 235 LinkedBlockingQueue<Integer> resultListener = new LinkedBlockingQueue<>(1); 236 TextView showErrorStatusTextView = findViewById(R.id.showErrorStatus); 237 TextView textView = findViewById(R.id.text_id); 238 mSatelliteManager.setDeviceAlignedWithSatellite(true); 239 if (SatelliteTestApp.getTestSatelliteService() != null) { 240 SatelliteTestApp.getTestSatelliteService().sendOnPendingDatagrams(); 241 } 242 mSatelliteManager.requestEnabled( 243 new EnableRequestAttributes.Builder(true).setDemoMode(true).build(), 244 Runnable::run, resultListener::offer); 245 try { 246 Integer value = resultListener.poll(TIMEOUT, TimeUnit.MILLISECONDS); 247 if (value == null) { 248 showErrorStatusTextView.setText("Timed out to enable the satellite"); 249 return; 250 } else if (value != SatelliteResult.SATELLITE_RESULT_SUCCESS) { 251 showErrorStatusTextView.setText("Failed to enable satellite, error = " 252 + SatelliteErrorUtils.mapError(value)); 253 return; 254 } 255 resultListener.clear(); 256 Log.d(TAG, "Poll to check queue is cleared = " 257 + resultListener.poll(TIMEOUT, TimeUnit.MILLISECONDS)); 258 } catch (InterruptedException e) { 259 showErrorStatusTextView.setText("Enable SatelliteService exception caught = " + e); 260 return; 261 } 262 mSatelliteManager.pollPendingDatagrams(Runnable::run, resultListener::offer); 263 try { 264 Integer value = resultListener.poll(TIMEOUT, TimeUnit.MILLISECONDS); 265 if (value == null) { 266 textView.setText("Timed out for poll message"); 267 } else if (value != SatelliteResult.SATELLITE_RESULT_SUCCESS) { 268 textView.setText("Failed to pollPendingDatagrams with error = " 269 + SatelliteErrorUtils.mapError(value)); 270 } else { 271 textView.setText("pollPendingDatagrams is successful"); 272 } 273 } catch (InterruptedException e) { 274 textView.setText("pollPendingDatagrams exception caught =" + e); 275 } 276 } 277 sendDatagramApp(View view)278 private void sendDatagramApp(View view) { 279 TextView textView = findViewById(R.id.text_id); 280 mSatelliteManager.setDeviceAlignedWithSatellite(true); 281 LinkedBlockingQueue<Integer> resultListener = new LinkedBlockingQueue<>(1); 282 String mText = "This is a test datagram message"; 283 SatelliteDatagram datagram = new SatelliteDatagram(mText.getBytes()); 284 mSatelliteManager.sendDatagram(SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE, 285 datagram, true, Runnable::run, resultListener::offer); 286 try { 287 Integer value = resultListener.poll(TIMEOUT, TimeUnit.MILLISECONDS); 288 if (value == null) { 289 textView.setText("Timed out for sendDatagram"); 290 } else if (value != SatelliteResult.SATELLITE_RESULT_SUCCESS) { 291 textView.setText("Failed to sendDatagram with error = " 292 + SatelliteErrorUtils.mapError(value)); 293 } else { 294 textView.setText("sendDatagram is successful"); 295 } 296 } catch (InterruptedException e) { 297 textView.setText("sendDatagram exception caught =" + e); 298 } 299 } 300 registerForIncomingDatagramApp(View view)301 private void registerForIncomingDatagramApp(View view) { 302 int result = mSatelliteManager.registerForIncomingDatagram(Runnable::run, 303 mDatagramCallback); 304 TextView textView = findViewById(R.id.text_id); 305 if (result == 0) { 306 textView.setText("registerForIncomingDatagram is successful"); 307 } else { 308 textView.setText("Status for registerForIncomingDatagram : " 309 + SatelliteErrorUtils.mapError(result)); 310 } 311 } 312 unregisterForIncomingDatagramApp(View view)313 private void unregisterForIncomingDatagramApp(View view) { 314 mSatelliteManager.unregisterForIncomingDatagram(mDatagramCallback); 315 TextView textView = findViewById(R.id.text_id); 316 textView.setText("unregisterForIncomingDatagram is successful"); 317 } 318 showDatagramSendStateTransitionApp(View view)319 private void showDatagramSendStateTransitionApp(View view) { 320 TextView textView = findViewById(R.id.text_id); 321 textView.setText("Last datagram send state transition is : " 322 + mShowDatagramSendStateTransition); 323 } 324 showDatagramReceiveStateTransitionApp(View view)325 private void showDatagramReceiveStateTransitionApp(View view) { 326 TextView textView = findViewById(R.id.text_id); 327 textView.setText("Last datagram receive state transition is : " 328 + mShowDatagramReceiveStateTransition); 329 } 330 registerForModemStateChangedApp(View view)331 private void registerForModemStateChangedApp(View view) { 332 int result = mSatelliteManager.registerForModemStateChanged(Runnable::run, 333 mStateCallback); 334 TextView textView = findViewById(R.id.text_id); 335 if (result == 0) { 336 textView.setText("registerForModemStateChanged is successful"); 337 } else { 338 textView.setText("Status for registerForModemStateChanged : " 339 + SatelliteErrorUtils.mapError(result)); 340 } 341 } 342 unregisterForModemStateChangedApp(View view)343 private void unregisterForModemStateChangedApp(View view) { 344 mSatelliteManager.unregisterForModemStateChanged(mStateCallback); 345 TextView textView = findViewById(R.id.text_id); 346 textView.setText("unregisterForModemStateChanged is successful"); 347 } 348 showSatelliteModemStateTransitionApp(View view)349 private void showSatelliteModemStateTransitionApp(View view) { 350 TextView textView = findViewById(R.id.text_id); 351 textView.setText( 352 "Last modem transition state is: " + mShowSatelliteModemStateTransition); 353 } 354 getSatelliteModemStateName(@atelliteManager.SatelliteModemState int state)355 private String getSatelliteModemStateName(@SatelliteManager.SatelliteModemState int state) { 356 switch (state) { 357 case SatelliteManager.SATELLITE_MODEM_STATE_IDLE: 358 return "IDLE"; 359 case SatelliteManager.SATELLITE_MODEM_STATE_LISTENING: 360 return "LISTENING"; 361 case SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING: 362 return "DATAGRAM_TRANSFERRING"; 363 case SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_RETRYING: 364 return "DATAGRAM_RETRYING"; 365 case SatelliteManager.SATELLITE_MODEM_STATE_OFF: 366 return "OFF"; 367 case SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE: 368 return "UNAVAILABLE"; 369 default: return "UNKNOWN"; 370 } 371 } 372 getSatelliteModemStateTransition(LinkedList<Integer> states)373 private String getSatelliteModemStateTransition(LinkedList<Integer> states) { 374 StringBuilder sb = new StringBuilder(); 375 for (int state : states) { 376 sb.append(getSatelliteModemStateName(state)); 377 sb.append("=>"); 378 } 379 if (!sb.isEmpty()) { 380 sb.delete(sb.length() - 2, sb.length()); 381 } 382 return sb.toString(); 383 } 384 getDatagramTransferStateName( @atelliteManager.SatelliteDatagramTransferState int state)385 private String getDatagramTransferStateName( 386 @SatelliteManager.SatelliteDatagramTransferState int state) { 387 switch (state) { 388 case SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE: return "IDLE"; 389 case SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING: return "SENDING"; 390 case SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS: return "SEND_SUCCESS"; 391 case SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED: return "SEND_FAILED"; 392 case SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING: return "RECEIVING"; 393 case SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_SUCCESS: return "RECEIVE_SUCCESS"; 394 case SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_NONE: return "RECEIVE_NONE"; 395 case SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED: return "RECEIVE_FAILED"; 396 default: return "UNKNOWN"; 397 } 398 } 399 getTransferStateTransition(LinkedList<Integer> states)400 private String getTransferStateTransition(LinkedList<Integer> states) { 401 StringBuilder sb = new StringBuilder(); 402 for (int state : states) { 403 sb.append(getDatagramTransferStateName(state)); 404 sb.append("=>"); 405 } 406 if (!sb.isEmpty()) { 407 sb.delete(sb.length() - 2, sb.length()); 408 } 409 return sb.toString(); 410 } 411 412 @Override onResume()413 protected void onResume() { 414 super.onResume(); 415 SharedPreferences sh = getSharedPreferences("TestSatelliteSharedPref", MODE_PRIVATE); 416 String modemStateTransition = sh.getString("modem_state", 417 mShowSatelliteModemStateTransition); 418 String datagramSendStateTransition = sh.getString("datagram_send_state", 419 mShowDatagramSendStateTransition); 420 String datagramReceiveStateTransition = sh.getString("datagram_receive_state", 421 mShowDatagramReceiveStateTransition); 422 423 // Setting the fetched data 424 mShowSatelliteModemStateTransition = modemStateTransition; 425 mShowDatagramSendStateTransition = datagramSendStateTransition; 426 mShowDatagramReceiveStateTransition = datagramReceiveStateTransition; 427 } 428 429 @Override onPause()430 protected void onPause() { 431 super.onPause(); 432 SharedPreferences sharedPreferences = getSharedPreferences("TestSatelliteSharedPref", 433 MODE_PRIVATE); 434 SharedPreferences.Editor myEdit = sharedPreferences.edit(); 435 436 myEdit.putString("modem_state", mShowSatelliteModemStateTransition); 437 myEdit.putString("datagram_send_state", mShowDatagramSendStateTransition); 438 myEdit.putString("datagram_receive_state", mShowDatagramReceiveStateTransition); 439 myEdit.apply(); 440 } 441 onDestroy()442 protected void onDestroy() { 443 super.onDestroy(); 444 SharedPreferences sharedPreferences = getSharedPreferences("TestSatelliteSharedPref", 445 MODE_PRIVATE); 446 final SharedPreferences.Editor sharedPrefsEditor = sharedPreferences.edit(); 447 448 sharedPrefsEditor.remove("modem_state"); 449 sharedPrefsEditor.remove("datagram_send_state"); 450 sharedPrefsEditor.remove("datagram_receive_state"); 451 sharedPrefsEditor.commit(); 452 } 453 } 454