[automerger skipped] Merge "Import translations. DO NOT MERGE ANYWHERE" into udc-mainline-prod am: 8f9fa4dfe2 -s ours
am skip reason: subject contains skip directive
Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/services/Telephony/+/22979516
Change-Id: I3962c611f0750039cccd5990f8db7b5cdb46743f
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/src/com/android/phone/CarrierConfigLoader.java b/src/com/android/phone/CarrierConfigLoader.java
index fa85f27..bc42a93 100644
--- a/src/com/android/phone/CarrierConfigLoader.java
+++ b/src/com/android/phone/CarrierConfigLoader.java
@@ -39,6 +39,7 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.PermissionEnforcer;
import android.os.PersistableBundle;
import android.os.Process;
import android.os.RemoteException;
@@ -695,6 +696,7 @@
*/
@VisibleForTesting
/* package */ CarrierConfigLoader(@NonNull Context context, @NonNull Looper looper) {
+ super(PermissionEnforcer.fromContext(context));
mContext = context;
mPlatformCarrierConfigPackage =
mContext.getString(R.string.platform_carrier_config_package);
@@ -1408,11 +1410,11 @@
return configSubset;
}
+ @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_PHONE_STATE)
@Override
public void overrideConfig(int subscriptionId, @Nullable PersistableBundle overrides,
boolean persistent) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.MODIFY_PHONE_STATE, null);
+ overrideConfig_enforcePermission();
int phoneId = SubscriptionManager.getPhoneId(subscriptionId);
if (!SubscriptionManager.isValidPhoneId(phoneId)) {
logd("Ignore invalid phoneId: " + phoneId + " for subId: " + subscriptionId);
@@ -1478,10 +1480,10 @@
updateConfigForPhoneId(phoneId);
}
+ @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_PHONE_STATE)
@Override
public void updateConfigForPhoneId(int phoneId, @NonNull String simState) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.MODIFY_PHONE_STATE, null);
+ updateConfigForPhoneId_enforcePermission();
logdWithLocalLog("Update config for phoneId: " + phoneId + " simState: " + simState);
if (!SubscriptionManager.isValidPhoneId(phoneId)) {
throw new IllegalArgumentException("Invalid phoneId: " + phoneId);
@@ -1502,12 +1504,11 @@
}
}
+ @android.annotation.EnforcePermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
@Override
@NonNull
public String getDefaultCarrierServicePackageName() {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
- "getDefaultCarrierServicePackageName");
+ getDefaultCarrierServicePackageName_enforcePermission();
return mPlatformCarrierConfigPackage;
}
diff --git a/src/com/android/phone/PhoneUtils.java b/src/com/android/phone/PhoneUtils.java
index 4826d2b..0c8a9c7 100644
--- a/src/com/android/phone/PhoneUtils.java
+++ b/src/com/android/phone/PhoneUtils.java
@@ -703,8 +703,12 @@
}
public static PhoneAccountHandle makePstnPhoneAccountHandle(Phone phone) {
- return makePstnPhoneAccountHandleWithPrefix(phone, "",
- false, phone.getUserHandle());
+ if (phone == null) {
+ return null;
+ } else {
+ return makePstnPhoneAccountHandleWithPrefix(phone, "",
+ false, phone.getUserHandle());
+ }
}
public static PhoneAccountHandle makePstnPhoneAccountHandleWithPrefix(
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 02c413e..7bf7234 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -2250,8 +2250,7 @@
.setVideoState(videoState)
.setIntentExtras(extras)
.setRttTextStream(mNormalCallConnection.getRttTextStream())
- .setIsWpsCall(NormalCallDomainSelectionConnection
- .isWpsCall(number))
+ .setIsWpsCall(PhoneNumberUtils.isWpsCallNumber(number))
.build(),
mNormalCallConnection::registerForCallEvents);
@@ -2312,7 +2311,7 @@
// Check and select same domain as ongoing call on the same subscription (if exists)
int activeCallDomain = getActiveCallDomain(phone.getSubId());
if (activeCallDomain != NetworkRegistrationInfo.DOMAIN_UNKNOWN
- && !NormalCallDomainSelectionConnection.isWpsCall(number)) {
+ && !PhoneNumberUtils.isWpsCallNumber(number)) {
Log.d(LOG_TAG, "Selecting same domain as ongoing call on same subId");
mNormalCallConnection = connection;
handleOutgoingCallConnectionByCallDomainSelection(
diff --git a/src/com/android/services/telephony/domainselection/NormalCallDomainSelector.java b/src/com/android/services/telephony/domainselection/NormalCallDomainSelector.java
index f176d90..70ad38e 100644
--- a/src/com/android/services/telephony/domainselection/NormalCallDomainSelector.java
+++ b/src/com/android/services/telephony/domainselection/NormalCallDomainSelector.java
@@ -28,13 +28,12 @@
import android.telephony.DisconnectCause;
import android.telephony.DomainSelectionService.SelectionAttributes;
import android.telephony.NetworkRegistrationInfo;
+import android.telephony.PhoneNumberUtils;
import android.telephony.ServiceState;
import android.telephony.SubscriptionManager;
import android.telephony.TransportSelectorCallback;
import android.telephony.ims.ImsReasonInfo;
-import com.android.internal.telephony.domainselection.NormalCallDomainSelectionConnection;
-
/**
* Implements domain selector for outgoing non-emergency calls.
*/
@@ -375,9 +374,7 @@
// Handle voice call.
if (mImsStateTracker.isImsVoiceCapable()) {
logd("IMS is voice capable");
- // TODO(b/266175810) Remove this dependency.
- if (NormalCallDomainSelectionConnection
- .isWpsCall(mSelectionAttributes.getNumber())) {
+ if (PhoneNumberUtils.isWpsCallNumber(mSelectionAttributes.getNumber())) {
handleWpsCall();
} else {
notifyPsSelected();
diff --git a/testapps/GbaTestApp/Android.bp b/testapps/GbaTestApp/Android.bp
index 76e02a0..72f7cc4 100644
--- a/testapps/GbaTestApp/Android.bp
+++ b/testapps/GbaTestApp/Android.bp
@@ -22,7 +22,6 @@
static_libs: [
"androidx.appcompat_appcompat",
"androidx-constraintlayout_constraintlayout",
- "ub-uiautomator",
],
srcs: ["src/**/*.java"],
javacflags: ["-parameters"],
diff --git a/testapps/TestSatelliteApp/Android.bp b/testapps/TestSatelliteApp/Android.bp
new file mode 100644
index 0000000..fd3c424
--- /dev/null
+++ b/testapps/TestSatelliteApp/Android.bp
@@ -0,0 +1,17 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_app {
+ name: "SatelliteTestApp",
+ system_ext_specific: true,
+ platform_apis: true,
+ manifest: "AndroidManifest.xml",
+ srcs: [
+ "src/**/*.java",
+ "src/**/I*.aidl",
+ ],
+ owner: "google",
+ privileged: true,
+ certificate: "platform",
+}
diff --git a/testapps/TestSatelliteApp/AndroidManifest.xml b/testapps/TestSatelliteApp/AndroidManifest.xml
new file mode 100644
index 0000000..278d102
--- /dev/null
+++ b/testapps/TestSatelliteApp/AndroidManifest.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.phone.testapps.satellitetestapp">
+ <uses-permission android:name="android.permission.BIND_SATELLITE_SERVICE"/>
+ <uses-permission android:name="android.permission.SATELLITE_COMMUNICATION"/>
+ <application android:label="SatelliteTestApp">
+ <activity android:name=".SatelliteTestApp"
+ android:label="SatelliteTestApp"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+
+ <service android:name=".TestSatelliteService"
+ android:directBootAware="true"
+ android:persistent="true"
+ android:permission="android.permission.BIND_SATELLITE_SERVICE"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.telephony.satellite.SatelliteService"/>
+ </intent-filter>
+ </service>
+
+ <activity android:name=".SatelliteControl" />
+ <activity android:name=".SatelliteTransmissionUpdates" />
+ <activity android:name=".Datagram" />
+ <activity android:name=".Provisioning" />
+ <activity android:name=".SatelliteModemState" />
+ </application>
+</manifest>
diff --git a/testapps/TestSatelliteApp/res/layout/activity_Datagram.xml b/testapps/TestSatelliteApp/res/layout/activity_Datagram.xml
new file mode 100644
index 0000000..5cfe7d9
--- /dev/null
+++ b/testapps/TestSatelliteApp/res/layout/activity_Datagram.xml
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:gravity="center"
+ android:paddingLeft="4dp">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" android:layout_weight="0"
+ android:textColor="@android:color/holo_blue_dark"
+ android:textSize="20dp"
+ android:text="Datagram APIs"/>
+ <Button
+ android:id="@+id/pollPendingSatelliteDatagrams"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingRight="4dp"
+ android:text="@string/pollPendingSatelliteDatagrams"/>
+ <Button
+ android:id="@+id/multiplePollPendingSatelliteDatagrams"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingRight="4dp"
+ android:text="@string/multiplePollPendingSatelliteDatagrams"/>
+ <Button
+ android:id="@+id/sendSatelliteDatagram"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingRight="4dp"
+ android:text="@string/sendSatelliteDatagram"/>
+ <Button
+ android:id="@+id/multipleSendSatelliteDatagram"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingRight="4dp"
+ android:text="@string/multipleSendSatelliteDatagram"/>
+ <Button
+ android:id="@+id/multipleSendReceiveSatelliteDatagram"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingRight="4dp"
+ android:text="@string/multipleSendReceiveSatelliteDatagram"/>
+ <Button
+ android:id="@+id/registerForSatelliteDatagram"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingRight="4dp"
+ android:text="@string/registerForSatelliteDatagram"/>
+ <Button
+ android:id="@+id/unregisterForSatelliteDatagram"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingRight="4dp"
+ android:text="@string/unregisterForSatelliteDatagram"/>
+ <Button
+ android:id="@+id/Back"
+ android:onClick="Back"
+ android:textColor="@android:color/holo_blue_dark"
+ android:layout_marginTop="100dp"
+ android:layout_gravity="center"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingRight="4dp"
+ android:text="@string/Back"/>
+ <TextView
+ android:id="@+id/text_id"
+ android:layout_width="300dp"
+ android:layout_height="200dp"
+ android:capitalize="characters"
+ android:textColor="@android:color/holo_blue_light"
+ android:layout_centerVertical="true"
+ android:textSize="15dp" />
+ </LinearLayout>
+</LinearLayout>
diff --git a/testapps/TestSatelliteApp/res/layout/activity_Provisioning.xml b/testapps/TestSatelliteApp/res/layout/activity_Provisioning.xml
new file mode 100644
index 0000000..c62aebf
--- /dev/null
+++ b/testapps/TestSatelliteApp/res/layout/activity_Provisioning.xml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:gravity="center"
+ android:paddingLeft="4dp">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" android:layout_weight="0"
+ android:textColor="@android:color/holo_blue_dark"
+ android:textSize="20dp"
+ android:text="Provisioning APIs"/>
+ <Button
+ android:id="@+id/provisionSatelliteService"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingRight="4dp"
+ android:text="@string/provisionSatelliteService"/>
+ <Button
+ android:id="@+id/deprovisionSatelliteService"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingRight="4dp"
+ android:text="@string/deprovisionSatelliteService"/>
+ <Button
+ android:id="@+id/requestIsSatelliteProvisioned"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingRight="4dp"
+ android:text="@string/requestIsSatelliteProvisioned"/>
+ <Button
+ android:id="@+id/registerForSatelliteProvisionStateChanged"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingRight="4dp"
+ android:text="@string/registerForSatelliteProvisionStateChanged"/>
+ <Button
+ android:id="@+id/unregisterForSatelliteProvisionStateChanged"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingRight="4dp"
+ android:text="@string/unregisterForSatelliteProvisionStateChanged"/>
+ <Button
+ android:id="@+id/Back"
+ android:onClick="Back"
+ android:textColor="@android:color/holo_blue_dark"
+ android:layout_marginTop="100dp"
+ android:layout_gravity="center"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingRight="4dp"
+ android:text="@string/Back"/>
+ <TextView
+ android:id="@+id/text_id"
+ android:layout_width="300dp"
+ android:layout_height="200dp"
+ android:capitalize="characters"
+ android:textColor="@android:color/holo_blue_light"
+ android:layout_centerVertical="true"
+ android:textSize="15dp" />
+ </LinearLayout>
+</LinearLayout>
diff --git a/testapps/TestSatelliteApp/res/layout/activity_SatelliteControl.xml b/testapps/TestSatelliteApp/res/layout/activity_SatelliteControl.xml
new file mode 100644
index 0000000..1484ba7
--- /dev/null
+++ b/testapps/TestSatelliteApp/res/layout/activity_SatelliteControl.xml
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:gravity="center"
+ android:paddingLeft="4dp">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" android:layout_weight="0"
+ android:textColor="@android:color/holo_blue_dark"
+ android:textSize="20dp"
+ android:text="Satellite Control APIs"/>
+ <Button
+ android:id="@+id/requestSatelliteEnabled"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingRight="4dp"
+ android:text="@string/requestSatelliteEnabled"/>
+ <Button
+ android:id="@+id/requestIsSatelliteEnabled"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingRight="4dp"
+ android:text="@string/requestIsSatelliteEnabled"/>
+ <Button
+ android:id="@+id/requestIsDemoModeEnabled"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingRight="4dp"
+ android:text="@string/requestIsDemoModeEnabled"/>
+ <Button
+ android:id="@+id/requestIsSatelliteSupported"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingRight="4dp"
+ android:text="@string/requestIsSatelliteSupported"/>
+ <Button
+ android:id="@+id/requestSatelliteCapabilities"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingRight="4dp"
+ android:text="@string/requestSatelliteCapabilities"/>
+ <Button
+ android:id="@+id/requestIsSatelliteCommunicationAllowedForCurrentLocation"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingRight="4dp"
+ android:text="@string/requestIsSatelliteCommunicationAllowedForCurrentLocation"/>
+ <Button
+ android:id="@+id/requestTimeForNextSatelliteVisibility"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingRight="4dp"
+ android:text="@string/requestTimeForNextSatelliteVisibility"/>
+ <Button
+ android:id="@+id/Back"
+ android:onClick="Back"
+ android:textColor="@android:color/holo_blue_dark"
+ android:layout_marginTop="100dp"
+ android:layout_gravity="center"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingRight="4dp"
+ android:text="@string/Back"/>
+ <TextView
+ android:id="@+id/text_id"
+ android:layout_width="300dp"
+ android:layout_height="200dp"
+ android:capitalize="characters"
+ android:textColor="@android:color/holo_blue_light"
+ android:layout_centerVertical="true"
+ android:textSize="15dp" />
+ </LinearLayout>
+</LinearLayout>
diff --git a/testapps/TestSatelliteApp/res/layout/activity_SatelliteModemState.xml b/testapps/TestSatelliteApp/res/layout/activity_SatelliteModemState.xml
new file mode 100644
index 0000000..5e70ef3
--- /dev/null
+++ b/testapps/TestSatelliteApp/res/layout/activity_SatelliteModemState.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:gravity="center"
+ android:paddingLeft="4dp">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" android:layout_weight="0"
+ android:textColor="@android:color/holo_blue_dark"
+ android:textSize="20dp"
+ android:text="SatelliteModemState APIs"/>
+ <Button
+ android:id="@+id/registerForSatelliteModemStateChanged"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingRight="4dp"
+ android:text="@string/registerForSatelliteModemStateChanged"/>
+ <Button
+ android:id="@+id/unregisterForSatelliteModemStateChanged"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingRight="4dp"
+ android:text="@string/unregisterForSatelliteModemStateChanged"/>
+ <Button
+ android:id="@+id/Back"
+ android:onClick="Back"
+ android:textColor="@android:color/holo_blue_dark"
+ android:layout_marginTop="100dp"
+ android:layout_gravity="center"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingRight="4dp"
+ android:text="@string/Back"/>
+ <TextView
+ android:id="@+id/text_id"
+ android:layout_width="300dp"
+ android:layout_height="200dp"
+ android:capitalize="characters"
+ android:textColor="@android:color/holo_blue_light"
+ android:layout_centerVertical="true"
+ android:textSize="15dp" />
+ </LinearLayout>
+</LinearLayout>
+
diff --git a/testapps/TestSatelliteApp/res/layout/activity_SatelliteTestApp.xml b/testapps/TestSatelliteApp/res/layout/activity_SatelliteTestApp.xml
new file mode 100644
index 0000000..f9a0809
--- /dev/null
+++ b/testapps/TestSatelliteApp/res/layout/activity_SatelliteTestApp.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:paddingLeft="4dp">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" android:layout_weight="0"
+ android:textColor="@android:color/holo_blue_dark"
+ android:textSize="20dp"
+ android:text="Available Satellite APIs"/>
+ <Button
+ android:id="@+id/SatelliteControl"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingRight="4dp"
+ android:text="@string/SatelliteControl"/>
+ <Button
+ android:id="@+id/SatelliteTransmissionUpdates"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingRight="4dp"
+ android:text="@string/SatelliteTransmissionUpdates"/>
+ <Button
+ android:id="@+id/Datagram"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingRight="4dp"
+ android:text="@string/Datagram"/>
+ <Button
+ android:id="@+id/Provisioning"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingRight="4dp"
+ android:text="@string/Provisioning"/>
+ <Button
+ android:id="@+id/SatelliteModemState"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingRight="4dp"
+ android:text="@string/SatelliteModemState"/>
+ </LinearLayout>
+</LinearLayout>
diff --git a/testapps/TestSatelliteApp/res/layout/activity_SatelliteTransmissionUpdates.xml b/testapps/TestSatelliteApp/res/layout/activity_SatelliteTransmissionUpdates.xml
new file mode 100644
index 0000000..4eb3851
--- /dev/null
+++ b/testapps/TestSatelliteApp/res/layout/activity_SatelliteTransmissionUpdates.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:gravity="center"
+ android:paddingLeft="4dp">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" android:layout_weight="0"
+ android:textColor="@android:color/holo_blue_dark"
+ android:textSize="20dp"
+ android:text="SatelliteTransmissionUpdates APIs"/>
+ <Button
+ android:id="@+id/startSatelliteTransmissionUpdates"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingRight="4dp"
+ android:text="@string/startSatelliteTransmissionUpdates"/>
+ <Button
+ android:id="@+id/stopSatelliteTransmissionUpdates"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingRight="4dp"
+ android:text="@string/stopSatelliteTransmissionUpdates"/>
+ <Button
+ android:id="@+id/Back"
+ android:onClick="Back"
+ android:textColor="@android:color/holo_blue_dark"
+ android:layout_marginTop="100dp"
+ android:layout_gravity="center"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingRight="4dp"
+ android:text="@string/Back"/>
+ <TextView
+ android:id="@+id/text_id"
+ android:layout_width="300dp"
+ android:layout_height="200dp"
+ android:capitalize="characters"
+ android:textColor="@android:color/holo_blue_light"
+ android:layout_centerVertical="true"
+ android:textSize="15dp" />
+ </LinearLayout>
+</LinearLayout>
diff --git a/testapps/TestSatelliteApp/res/values/donottranslate_strings.xml b/testapps/TestSatelliteApp/res/values/donottranslate_strings.xml
new file mode 100644
index 0000000..bd6f389
--- /dev/null
+++ b/testapps/TestSatelliteApp/res/values/donottranslate_strings.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<resources>
+ <string name="SatelliteControl">SatelliteControl APIs</string>
+ <string name="SatelliteTransmissionUpdates">SatelliteTransmissionUpdates APIs</string>
+ <string name="Datagram">Datagram APIs</string>
+ <string name="Provisioning">Provisioning APIs</string>
+ <string name="SatelliteModemState">SatelliteModemState APIs</string>
+
+ <string name="requestSatelliteEnabled">requestSatelliteEnabled</string>
+ <string name="requestIsSatelliteEnabled">requestIsSatelliteEnabled</string>
+ <string name="requestIsDemoModeEnabled">requestIsDemoModeEnabled</string>
+ <string name="requestIsSatelliteSupported">requestIsSatelliteSupported</string>
+ <string name="requestSatelliteCapabilities">requestSatelliteCapabilities</string>
+ <string name="requestIsSatelliteCommunicationAllowedForCurrentLocation">requestIsSatelliteCommunicationAllowedForCurrentLocation</string>
+ <string name="requestTimeForNextSatelliteVisibility">requestTimeForNextSatelliteVisibility</string>
+
+ <string name="startSatelliteTransmissionUpdates">startSatelliteTransmissionUpdates</string>
+ <string name="stopSatelliteTransmissionUpdates">stopSatelliteTransmissionUpdates</string>
+
+ <string name="pollPendingSatelliteDatagrams">pollPendingSatelliteDatagrams</string>
+ <string name="multiplePollPendingSatelliteDatagrams">multiplePollPendingSatelliteDatagrams</string>
+ <string name="sendSatelliteDatagram">sendSatelliteDatagram</string>
+ <string name="multipleSendSatelliteDatagram">multipleSendSatelliteDatagram</string>
+ <string name="multipleSendReceiveSatelliteDatagram">multipleSendReceiveSatelliteDatagram</string>
+ <string name="registerForSatelliteDatagram">registerForSatelliteDatagram</string>
+ <string name="unregisterForSatelliteDatagram">unregisterForSatelliteDatagram</string>
+
+ <string name="provisionSatelliteService">provisionSatelliteService</string>
+ <string name="deprovisionSatelliteService">deprovisionSatelliteService</string>
+ <string name="requestIsSatelliteProvisioned">requestIsSatelliteProvisioned</string>
+ <string name="registerForSatelliteProvisionStateChanged">registerForSatelliteProvisionStateChanged</string>
+ <string name="unregisterForSatelliteProvisionStateChanged">unregisterForSatelliteProvisionStateChanged</string>
+
+ <string name="registerForSatelliteModemStateChanged">registerForSatelliteModemStateChanged</string>
+ <string name="unregisterForSatelliteModemStateChanged">unregisterForSatelliteModemStateChanged</string>
+
+ <string name="Back">Back</string>
+</resources>
diff --git a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/Datagram.java b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/Datagram.java
new file mode 100644
index 0000000..1391c47
--- /dev/null
+++ b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/Datagram.java
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.phone.testapps.satellitetestapp;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.telephony.satellite.SatelliteDatagram;
+import android.telephony.satellite.SatelliteDatagramCallback;
+import android.telephony.satellite.SatelliteManager;
+import android.util.Log;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.TextView;
+
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+
+/**
+ * Activity related to Datagram APIs.
+ */
+public class Datagram extends Activity {
+
+ private static final String TAG = "Datagram";
+
+ private SatelliteManager mSatelliteManager;
+ private SatelliteDatagramCallbackTestApp mCallback;
+ private android.telephony.satellite.stub.SatelliteDatagram mReceivedDatagram;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mSatelliteManager = getSystemService(SatelliteManager.class);
+ mCallback = new SatelliteDatagramCallbackTestApp();
+
+ mReceivedDatagram = new android.telephony.satellite.stub.SatelliteDatagram();
+
+ setContentView(R.layout.activity_Datagram);
+ findViewById(R.id.pollPendingSatelliteDatagrams)
+ .setOnClickListener(this::pollPendingSatelliteDatagramsApp);
+ findViewById(R.id.multiplePollPendingSatelliteDatagrams)
+ .setOnClickListener(this::multiplePollPendingSatelliteDatagramsApp);
+ findViewById(R.id.sendSatelliteDatagram)
+ .setOnClickListener(this::sendSatelliteDatagramApp);
+ findViewById(R.id.multipleSendSatelliteDatagram)
+ .setOnClickListener(this::multipleSendSatelliteDatagramApp);
+ findViewById(R.id.multipleSendReceiveSatelliteDatagram)
+ .setOnClickListener(this::multipleSendReceiveSatelliteDatagramApp);
+ findViewById(R.id.registerForSatelliteDatagram)
+ .setOnClickListener(this::registerForSatelliteDatagramApp);
+ findViewById(R.id.unregisterForSatelliteDatagram)
+ .setOnClickListener(this::unregisterForSatelliteDatagramApp);
+ findViewById(R.id.Back).setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ startActivity(new Intent(Datagram.this, SatelliteTestApp.class));
+ }
+ });
+ }
+
+ protected static class SatelliteDatagramCallbackTestApp implements SatelliteDatagramCallback {
+ @Override
+ public void onSatelliteDatagramReceived(long datagramId, SatelliteDatagram datagram,
+ int pendingCount, Consumer<Void> callback) {
+ Log.d(TAG, "onSatelliteDatagramReceived in SatelliteTestApp: datagramId =" + datagramId
+ + ", datagram =" + datagram + ", pendingCount=" + pendingCount);
+ }
+ }
+
+ private void pollPendingSatelliteDatagramsApp(View view) {
+ SatelliteTestApp.getTestSatelliteService().sendOnPendingDatagrams();
+ SatelliteTestApp.getTestSatelliteService().sendOnSatelliteDatagramReceived(
+ mReceivedDatagram, 0);
+ LinkedBlockingQueue<Integer> resultListener = new LinkedBlockingQueue<>(1);
+ mSatelliteManager.pollPendingSatelliteDatagrams(Runnable::run, resultListener::offer);
+ try {
+ Integer value = resultListener.poll(1000, TimeUnit.MILLISECONDS);
+ TextView textView = findViewById(R.id.text_id);
+ if (value == 0) {
+ textView.setText("pollPendingSatelliteDatagrams is Successful");
+ } else {
+ textView.setText("Status for pollPendingSatelliteDatagrams : "
+ + SatelliteErrorUtils.mapError(value));
+ }
+ } catch (InterruptedException e) {
+ Log.e(TAG, "exception caught =" + e);
+ }
+ }
+
+ private void multiplePollPendingSatelliteDatagramsApp(View view) {
+ SatelliteTestApp.getTestSatelliteService().sendOnPendingDatagrams();
+ SatelliteTestApp.getTestSatelliteService().sendOnSatelliteDatagramReceived(
+ mReceivedDatagram, 4);
+ LinkedBlockingQueue<Integer> resultListener = new LinkedBlockingQueue<>(1);
+ mSatelliteManager.pollPendingSatelliteDatagrams(Runnable::run, resultListener::offer);
+ SatelliteTestApp.getTestSatelliteService().sendOnSatelliteDatagramReceived(
+ mReceivedDatagram, 3);
+ mSatelliteManager.pollPendingSatelliteDatagrams(Runnable::run, resultListener::offer);
+ SatelliteTestApp.getTestSatelliteService().sendOnSatelliteDatagramReceived(
+ mReceivedDatagram, 2);
+ mSatelliteManager.pollPendingSatelliteDatagrams(Runnable::run, resultListener::offer);
+ SatelliteTestApp.getTestSatelliteService().sendOnSatelliteDatagramReceived(
+ mReceivedDatagram, 1);
+ mSatelliteManager.pollPendingSatelliteDatagrams(Runnable::run, resultListener::offer);
+ SatelliteTestApp.getTestSatelliteService().sendOnSatelliteDatagramReceived(
+ mReceivedDatagram, 0);
+ mSatelliteManager.pollPendingSatelliteDatagrams(Runnable::run, resultListener::offer);
+ try {
+ Integer value = resultListener.poll(1000, TimeUnit.MILLISECONDS);
+ TextView textView = findViewById(R.id.text_id);
+ if (value == 0) {
+ textView.setText("multiplePollPendingSatelliteDatagrams is Successful");
+ } else {
+ textView.setText("Status for multiplePollPendingSatelliteDatagrams : "
+ + SatelliteErrorUtils.mapError(value));
+ }
+ } catch (InterruptedException e) {
+ Log.e(TAG, "exception caught =" + e);
+ }
+ }
+
+ private void sendSatelliteDatagramApp(View view) {
+ LinkedBlockingQueue<Integer> resultListener = new LinkedBlockingQueue<>(1);
+ String mText = "This is a test datagram message";
+ SatelliteDatagram datagram = new SatelliteDatagram(mText.getBytes());
+ mSatelliteManager.sendSatelliteDatagram(SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE,
+ datagram, true, Runnable::run, resultListener::offer);
+ try {
+ Integer value = resultListener.poll(1000, TimeUnit.MILLISECONDS);
+ TextView textView = findViewById(R.id.text_id);
+ if (value == 0) {
+ textView.setText("sendSatelliteDatagram is Successful");
+ } else {
+ textView.setText("Status for sendSatelliteDatagram : "
+ + SatelliteErrorUtils.mapError(value));
+ }
+ } catch (InterruptedException e) {
+ Log.e(TAG, "exception caught =" + e);
+ }
+ }
+
+ private void multipleSendSatelliteDatagramApp(View view) {
+ LinkedBlockingQueue<Integer> resultListener = new LinkedBlockingQueue<>(1);
+ String mText = "This is a test datagram message";
+ SatelliteDatagram datagram = new SatelliteDatagram(mText.getBytes());
+ mSatelliteManager.sendSatelliteDatagram(SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE,
+ datagram, true, Runnable::run, resultListener::offer);
+ mSatelliteManager.sendSatelliteDatagram(SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE,
+ datagram, true, Runnable::run, resultListener::offer);
+ mSatelliteManager.sendSatelliteDatagram(SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE,
+ datagram, true, Runnable::run, resultListener::offer);
+ mSatelliteManager.sendSatelliteDatagram(SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE,
+ datagram, true, Runnable::run, resultListener::offer);
+ mSatelliteManager.sendSatelliteDatagram(SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE,
+ datagram, true, Runnable::run, resultListener::offer);
+ try {
+ Integer value = resultListener.poll(1000, TimeUnit.MILLISECONDS);
+ TextView textView = findViewById(R.id.text_id);
+ if (value == 0) {
+ textView.setText("multipleSendSatelliteDatagram is Successful");
+ } else {
+ textView.setText("Status for multipleSendSatelliteDatagram : "
+ + SatelliteErrorUtils.mapError(value));
+ }
+ } catch (InterruptedException e) {
+ Log.e(TAG, "exception caught =" + e);
+ }
+ }
+
+ private void multipleSendReceiveSatelliteDatagramApp(View view) {
+ LinkedBlockingQueue<Integer> resultListener = new LinkedBlockingQueue<>(1);
+ String mText = "This is a test datagram message";
+ SatelliteDatagram datagram = new SatelliteDatagram(mText.getBytes());
+ mSatelliteManager.sendSatelliteDatagram(SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE,
+ datagram, true, Runnable::run, resultListener::offer);
+ SatelliteTestApp.getTestSatelliteService().sendOnSatelliteDatagramReceived(
+ mReceivedDatagram, 4);
+ mSatelliteManager.pollPendingSatelliteDatagrams(Runnable::run, resultListener::offer);
+ mSatelliteManager.sendSatelliteDatagram(SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE,
+ datagram, true, Runnable::run, resultListener::offer);
+ SatelliteTestApp.getTestSatelliteService().sendOnSatelliteDatagramReceived(
+ mReceivedDatagram, 3);
+ mSatelliteManager.sendSatelliteDatagram(SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE,
+ datagram, true, Runnable::run, resultListener::offer);
+ SatelliteTestApp.getTestSatelliteService().sendOnSatelliteDatagramReceived(
+ mReceivedDatagram, 2);
+ mSatelliteManager.sendSatelliteDatagram(SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE,
+ datagram, true, Runnable::run, resultListener::offer);
+ SatelliteTestApp.getTestSatelliteService().sendOnSatelliteDatagramReceived(
+ mReceivedDatagram, 1);
+ mSatelliteManager.sendSatelliteDatagram(SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE,
+ datagram, true, Runnable::run, resultListener::offer);
+ SatelliteTestApp.getTestSatelliteService().sendOnSatelliteDatagramReceived(
+ mReceivedDatagram, 0);
+ try {
+ Integer value = resultListener.poll(1000, TimeUnit.MILLISECONDS);
+ TextView textView = findViewById(R.id.text_id);
+ if (value == 0) {
+ textView.setText("multipleSendReceiveSatelliteDatagram is Successful");
+ } else {
+ textView.setText("Status for multipleSendReceiveSatelliteDatagram : "
+ + SatelliteErrorUtils.mapError(value));
+ }
+ } catch (InterruptedException e) {
+ Log.e(TAG, "exception caught =" + e);
+ }
+ }
+
+ private void registerForSatelliteDatagramApp(View view) {
+ int result = mSatelliteManager.registerForSatelliteDatagram(Runnable::run, mCallback);
+ TextView textView = findViewById(R.id.text_id);
+ if (result == 0) {
+ textView.setText("registerForSatelliteDatagram is successful");
+ } else {
+ textView.setText("Status for registerForSatelliteDatagram : "
+ + SatelliteErrorUtils.mapError(result));
+ }
+ }
+
+ private void unregisterForSatelliteDatagramApp(View view) {
+ mSatelliteManager.unregisterForSatelliteDatagram(mCallback);
+ TextView textView = findViewById(R.id.text_id);
+ textView.setText("unregisterForSatelliteDatagram is successful");
+ }
+}
diff --git a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/ILocalSatelliteListener.aidl b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/ILocalSatelliteListener.aidl
new file mode 100644
index 0000000..2c320c8
--- /dev/null
+++ b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/ILocalSatelliteListener.aidl
@@ -0,0 +1,67 @@
+
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.phone.testapps.satellitetestapp;
+
+import android.telephony.satellite.stub.SatelliteDatagram;
+
+/**
+ * {@hide}
+ */
+oneway interface ILocalSatelliteListener {
+ /**
+ * Indicates that the remote service - SatelliteModemInterface - has successfully connected to
+ * the TestSatelliteService.
+ */
+ void onRemoteServiceConnected();
+
+ /**
+ * Indicates that TestSatelliteService has just received the request
+ * startSendingSatellitePointingInfo from Telephony.
+ */
+ void onStartSendingSatellitePointingInfo();
+
+ /**
+ * Indicates that TestSatelliteService has just received the request
+ * stopSendingSatellitePointingInfo from Telephony.
+ */
+ void onStopSendingSatellitePointingInfo();
+
+ /**
+ * Indicates that TestSatelliteService has just received the request
+ * pollPendingSatelliteDatagrams from Telephony.
+ */
+ void onPollPendingSatelliteDatagrams();
+
+ /**
+ * Indicates that TestSatelliteService has just received the request
+ * sendSatelliteDatagram from Telephony.
+ */
+ void onSendSatelliteDatagram(in SatelliteDatagram datagram, in boolean isEmergency);
+
+ /**
+ * Indicates that TestSatelliteService has just received the request
+ * requestSatelliteListeningEnabled from Telephony.
+ */
+ void onSatelliteListeningEnabled(in boolean enabled);
+
+ /**
+ * Indicates that TestSatelliteService has just received the request
+ * enableCellularModemWhileSatelliteModeIsOn from Telephony.
+ */
+ void onEnableCellularModemWhileSatelliteModeIsOn(in boolean enable);
+}
diff --git a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/Provisioning.java b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/Provisioning.java
new file mode 100644
index 0000000..b403b2c
--- /dev/null
+++ b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/Provisioning.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.phone.testapps.satellitetestapp;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.os.OutcomeReceiver;
+import android.telephony.satellite.SatelliteManager;
+import android.telephony.satellite.SatelliteProvisionStateCallback;
+import android.util.Log;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.TextView;
+
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Activity related to Provisioning APIs.
+ */
+public class Provisioning extends Activity {
+
+ private static final String TAG = "Provisioning";
+
+ private SatelliteManager mSatelliteManager;
+ private SatelliteProvisionStateCallbackTestApp mCallback;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mSatelliteManager = getSystemService(SatelliteManager.class);
+ mCallback = new SatelliteProvisionStateCallbackTestApp();
+
+ setContentView(R.layout.activity_Provisioning);
+ findViewById(R.id.provisionSatelliteService)
+ .setOnClickListener(this::provisionSatelliteServiceApp);
+ findViewById(R.id.deprovisionSatelliteService)
+ .setOnClickListener(this::deprovisionSatelliteServiceApp);
+ findViewById(R.id.requestIsSatelliteProvisioned)
+ .setOnClickListener(this::requestIsSatelliteProvisionedApp);
+ findViewById(R.id.registerForSatelliteProvisionStateChanged)
+ .setOnClickListener(this::registerForSatelliteProvisionStateChangedApp);
+ findViewById(R.id.unregisterForSatelliteProvisionStateChanged)
+ .setOnClickListener(this::unregisterForSatelliteProvisionStateChangedApp);
+ findViewById(R.id.Back).setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ startActivity(new Intent(Provisioning.this, SatelliteTestApp.class));
+ }
+ });
+ }
+
+ protected static class SatelliteProvisionStateCallbackTestApp implements
+ SatelliteProvisionStateCallback {
+ @Override
+ public void onSatelliteProvisionStateChanged(boolean provisioned) {
+ Log.d(TAG, "onSatelliteProvisionStateChanged in SatelliteTestApp: provisioned="
+ + provisioned);
+ }
+ }
+
+ private void provisionSatelliteServiceApp(View view) {
+ CancellationSignal cancellationSignal = new CancellationSignal();
+ LinkedBlockingQueue<Integer> error = new LinkedBlockingQueue<>(1);
+ String mText = "This is test provision data.";
+ byte[] testProvisionData = mText.getBytes();
+ mSatelliteManager.provisionSatelliteService("SATELLITE_TOKEN", testProvisionData,
+ cancellationSignal, Runnable::run, error::offer);
+ try {
+ Integer value = error.poll(1000, TimeUnit.MILLISECONDS);
+ TextView textView = findViewById(R.id.text_id);
+ textView.setText("Status for provisionSatelliteService : "
+ + SatelliteErrorUtils.mapError(value));
+ } catch (InterruptedException e) {
+ Log.e(TAG, "exception caught =" + e);
+ }
+ }
+
+ private void deprovisionSatelliteServiceApp(View view) {
+ LinkedBlockingQueue<Integer> error = new LinkedBlockingQueue<>(1);
+ mSatelliteManager.deprovisionSatelliteService("SATELLITE_TOKEN", Runnable::run,
+ error::offer);
+ try {
+ Integer value = error.poll(1000, TimeUnit.MILLISECONDS);
+ TextView textView = findViewById(R.id.text_id);
+ textView.setText("Status for deprovisionSatelliteService : "
+ + SatelliteErrorUtils.mapError(value));
+ } catch (InterruptedException e) {
+ Log.e(TAG, "exception caught =" + e);
+ }
+ }
+
+ private void requestIsSatelliteProvisionedApp(View view) {
+ final AtomicReference<Boolean> enabled = new AtomicReference<>();
+ final AtomicReference<Integer> errorCode = new AtomicReference<>();
+ OutcomeReceiver<Boolean, SatelliteManager.SatelliteException> mReceiver =
+ new OutcomeReceiver<>() {
+ @Override
+ public void onResult(Boolean result) {
+ enabled.set(result);
+ TextView textView = findViewById(R.id.text_id);
+ textView.setText("Status for requestIsSatelliteProvisioned result: "
+ + enabled.get());
+ }
+
+ @Override
+ public void onError(SatelliteManager.SatelliteException exception) {
+ errorCode.set(exception.getErrorCode());
+ TextView textView = findViewById(R.id.text_id);
+ textView.setText("Status for requestIsSatelliteProvisioned error : "
+ + SatelliteErrorUtils.mapError(errorCode.get()));
+ }
+ };
+ mSatelliteManager.requestIsSatelliteProvisioned(Runnable::run, mReceiver);
+ }
+
+ private void registerForSatelliteProvisionStateChangedApp(View view) {
+ int result = mSatelliteManager.registerForSatelliteProvisionStateChanged(Runnable::run,
+ mCallback);
+ TextView textView = findViewById(R.id.text_id);
+ textView.setText("Status for registerForSatelliteProvisionStateChanged : "
+ + SatelliteErrorUtils.mapError(result));
+ }
+
+ private void unregisterForSatelliteProvisionStateChangedApp(View view) {
+ mSatelliteManager.unregisterForSatelliteProvisionStateChanged(mCallback);
+ TextView textView = findViewById(R.id.text_id);
+ textView.setText("unregisterForSatelliteProvisionStateChanged is successful");
+ }
+}
diff --git a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/SatelliteControl.java b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/SatelliteControl.java
new file mode 100644
index 0000000..9cfbc6a
--- /dev/null
+++ b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/SatelliteControl.java
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.phone.testapps.satellitetestapp;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.OutcomeReceiver;
+import android.telephony.satellite.SatelliteCapabilities;
+import android.telephony.satellite.SatelliteManager;
+import android.util.Log;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.TextView;
+
+import java.time.Duration;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Activity related to SatelliteControl APIs for satellite.
+ */
+public class SatelliteControl extends Activity {
+
+ private static final String TAG = "SatelliteControl";
+
+ private SatelliteManager mSatelliteManager;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mSatelliteManager = getSystemService(SatelliteManager.class);
+
+ setContentView(R.layout.activity_SatelliteControl);
+ findViewById(R.id.requestSatelliteEnabled)
+ .setOnClickListener(this::requestSatelliteEnabledApp);
+ findViewById(R.id.requestIsSatelliteEnabled)
+ .setOnClickListener(this::requestIsSatelliteEnabledApp);
+ findViewById(R.id.requestIsDemoModeEnabled)
+ .setOnClickListener(this::requestIsDemoModeEnabledApp);
+ findViewById(R.id.requestIsSatelliteSupported)
+ .setOnClickListener(this::requestIsSatelliteSupportedApp);
+ findViewById(R.id.requestSatelliteCapabilities)
+ .setOnClickListener(this::requestSatelliteCapabilitiesApp);
+ findViewById(R.id.requestIsSatelliteCommunicationAllowedForCurrentLocation)
+ .setOnClickListener(
+ this::requestIsSatelliteCommunicationAllowedForCurrentLocationApp);
+ findViewById(R.id.requestTimeForNextSatelliteVisibility)
+ .setOnClickListener(this::requestTimeForNextSatelliteVisibilityApp);
+ findViewById(R.id.Back).setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ startActivity(new Intent(SatelliteControl.this, SatelliteTestApp.class));
+ }
+ });
+ }
+
+ private void requestSatelliteEnabledApp(View view) {
+ LinkedBlockingQueue<Integer> error = new LinkedBlockingQueue<>(1);
+ mSatelliteManager.requestSatelliteEnabled(true, true, Runnable::run, error::offer);
+ try {
+ Integer value = error.poll(1000, TimeUnit.MILLISECONDS);
+ TextView textView = findViewById(R.id.text_id);
+ if (value == 0) {
+ textView.setText("requestSatelliteEnabled is successful");
+ } else {
+ textView.setText("Status for requestSatelliteEnabled: "
+ + SatelliteErrorUtils.mapError(value));
+ }
+ } catch (InterruptedException e) {
+ Log.e(TAG, "exception caught =" + e);
+ }
+ }
+
+ private void requestIsSatelliteEnabledApp(View view) {
+ final AtomicReference<Boolean> enabled = new AtomicReference<>();
+ final AtomicReference<Integer> errorCode = new AtomicReference<>();
+ OutcomeReceiver<Boolean, SatelliteManager.SatelliteException> receiver =
+ new OutcomeReceiver<>() {
+ @Override
+ public void onResult(Boolean result) {
+ enabled.set(result);
+ TextView textView = findViewById(R.id.text_id);
+ if (enabled.get()) {
+ textView.setText("requestIsSatelliteEnabled is true");
+ } else {
+ textView.setText("Status for requestIsSatelliteEnabled result : "
+ + enabled.get());
+ }
+ }
+
+ @Override
+ public void onError(SatelliteManager.SatelliteException exception) {
+ errorCode.set(exception.getErrorCode());
+ TextView textView = findViewById(R.id.text_id);
+ textView.setText("Status for requestIsSatelliteEnabled error : "
+ + SatelliteErrorUtils.mapError(errorCode.get()));
+ }
+ };
+ mSatelliteManager.requestIsSatelliteEnabled(Runnable::run, receiver);
+ }
+
+ private void requestIsDemoModeEnabledApp(View view) {
+ final AtomicReference<Boolean> enabled = new AtomicReference<>();
+ final AtomicReference<Integer> errorCode = new AtomicReference<>();
+ OutcomeReceiver<Boolean, SatelliteManager.SatelliteException> receiver =
+ new OutcomeReceiver<>() {
+ @Override
+ public void onResult(Boolean result) {
+ enabled.set(result);
+ TextView textView = findViewById(R.id.text_id);
+ if (enabled.get()) {
+ textView.setText("requestIsDemoModeEnabled is true");
+ } else {
+ textView.setText("Status for requestIsDemoModeEnabled result : "
+ + enabled.get());
+ }
+ }
+
+ @Override
+ public void onError(SatelliteManager.SatelliteException exception) {
+ errorCode.set(exception.getErrorCode());
+ TextView textView = findViewById(R.id.text_id);
+ textView.setText("Status for requestIsDemoModeEnabled error : "
+ + SatelliteErrorUtils.mapError(errorCode.get()));
+ }
+ };
+ mSatelliteManager.requestIsDemoModeEnabled(Runnable::run, receiver);
+ }
+
+ private void requestIsSatelliteSupportedApp(View view) {
+ final AtomicReference<Boolean> enabled = new AtomicReference<>();
+ final AtomicReference<Integer> errorCode = new AtomicReference<>();
+ OutcomeReceiver<Boolean, SatelliteManager.SatelliteException> receiver =
+ new OutcomeReceiver<>() {
+ @Override
+ public void onResult(Boolean result) {
+ enabled.set(result);
+ TextView textView = findViewById(R.id.text_id);
+ if (enabled.get()) {
+ textView.setText("requestIsSatelliteSupported is true");
+ } else {
+ textView.setText("Status for requestIsSatelliteSupported result : "
+ + enabled.get());
+ }
+ }
+
+ @Override
+ public void onError(SatelliteManager.SatelliteException exception) {
+ errorCode.set(exception.getErrorCode());
+ TextView textView = findViewById(R.id.text_id);
+ textView.setText("Status for requestIsSatelliteSupported error : "
+ + SatelliteErrorUtils.mapError(errorCode.get()));
+ }
+ };
+ mSatelliteManager.requestIsSatelliteSupported(Runnable::run, receiver);
+ }
+
+ private void requestSatelliteCapabilitiesApp(View view) {
+ final AtomicReference<SatelliteCapabilities> capabilities = new AtomicReference<>();
+ final AtomicReference<Integer> errorCode = new AtomicReference<>();
+ OutcomeReceiver<SatelliteCapabilities, SatelliteManager.SatelliteException> receiver =
+ new OutcomeReceiver<>() {
+ @Override
+ public void onResult(SatelliteCapabilities result) {
+ capabilities.set(result);
+ TextView textView = findViewById(R.id.text_id);
+ textView.setText("Status for requestSatelliteCapabilities result: "
+ + capabilities.get());
+ }
+
+ @Override
+ public void onError(SatelliteManager.SatelliteException exception) {
+ errorCode.set(exception.getErrorCode());
+ TextView textView = findViewById(R.id.text_id);
+ textView.setText("Status for requestSatelliteCapabilities error : "
+ + SatelliteErrorUtils.mapError(errorCode.get()));
+ }
+ };
+ mSatelliteManager.requestSatelliteCapabilities(Runnable::run, receiver);
+ }
+
+ private void requestIsSatelliteCommunicationAllowedForCurrentLocationApp(View view) {
+ final AtomicReference<Boolean> enabled = new AtomicReference<>();
+ final AtomicReference<Integer> errorCode = new AtomicReference<>();
+ String display = "requestIsSatelliteCommunicationAllowedForCurrentLocation";
+ OutcomeReceiver<Boolean, SatelliteManager.SatelliteException> receiver =
+ new OutcomeReceiver<>() {
+ @Override
+ public void onResult(Boolean result) {
+ enabled.set(result);
+ TextView textView = findViewById(R.id.text_id);
+ if (enabled.get()) {
+ textView.setText(display + "is true");
+ } else {
+ textView.setText("Status for" + display + "result: " + enabled.get());
+ }
+
+ }
+
+ @Override
+ public void onError(SatelliteManager.SatelliteException exception) {
+ errorCode.set(exception.getErrorCode());
+ TextView textView = findViewById(R.id.text_id);
+ textView.setText("Status for" + display + "error: "
+ + SatelliteErrorUtils.mapError(errorCode.get()));
+ }
+ };
+ mSatelliteManager.requestIsSatelliteCommunicationAllowedForCurrentLocation(Runnable::run,
+ receiver);
+ }
+
+ private void requestTimeForNextSatelliteVisibilityApp(View view) {
+ final AtomicReference<Duration> nextVisibilityDuration = new AtomicReference<>();
+ final AtomicReference<Integer> errorCode = new AtomicReference<>();
+ OutcomeReceiver<Duration, SatelliteManager.SatelliteException> receiver =
+ new OutcomeReceiver<>() {
+ @Override
+ public void onResult(Duration result) {
+ nextVisibilityDuration.set(result);
+ TextView textView = findViewById(R.id.text_id);
+ textView.setText("Status for requestTimeForNextSatelliteVisibility result : "
+ + result.getSeconds());
+ }
+
+ @Override
+ public void onError(SatelliteManager.SatelliteException exception) {
+ errorCode.set(exception.getErrorCode());
+ TextView textView = findViewById(R.id.text_id);
+ textView.setText("Status for requestTimeForNextSatelliteVisibility error : "
+ + SatelliteErrorUtils.mapError(errorCode.get()));
+ }
+ };
+ mSatelliteManager.requestTimeForNextSatelliteVisibility(Runnable::run, receiver);
+ }
+}
diff --git a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/SatelliteErrorUtils.java b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/SatelliteErrorUtils.java
new file mode 100644
index 0000000..a52d3ba
--- /dev/null
+++ b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/SatelliteErrorUtils.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.phone.testapps.satellitetestapp;
+
+import android.telephony.satellite.stub.SatelliteError;
+import android.util.Log;
+
+/**
+ * Utils class for satellite error to display as string in SatelliteTestApp UI.
+ */
+public class SatelliteErrorUtils {
+ private static final String TAG = "SatelliteErrorUtils";
+
+ /**
+ * @param error int from the satellite manager.
+ * @return The converted SatelliteError for the testapp, result of the operation.
+ */
+ public static String mapError(int error) {
+ switch (error) {
+ case SatelliteError.ERROR_NONE:
+ return "SATELLITE_ERROR_NONE";
+ case SatelliteError.SATELLITE_ERROR:
+ return "SATELLITE_ERROR";
+ case SatelliteError.SERVER_ERROR:
+ return "SATELLITE_SERVER_ERROR";
+ case SatelliteError.SERVICE_ERROR:
+ return "SATELLITE_SERVICE_ERROR";
+ case SatelliteError.MODEM_ERROR:
+ return "SATELLITE_MODEM_ERROR";
+ case SatelliteError.NETWORK_ERROR:
+ return "SATELLITE_NETWORK_ERROR";
+ case SatelliteError.INVALID_TELEPHONY_STATE:
+ return "SATELLITE_INVALID_TELEPHONY_STATE";
+ case SatelliteError.INVALID_MODEM_STATE:
+ return "SATELLITE_INVALID_MODEM_STATE";
+ case SatelliteError.INVALID_ARGUMENTS:
+ return "SATELLITE_INVALID_ARGUMENTS";
+ case SatelliteError.REQUEST_FAILED:
+ return "SATELLITE_REQUEST_FAILED";
+ case SatelliteError.RADIO_NOT_AVAILABLE:
+ return "SATELLITE_RADIO_NOT_AVAILABLE";
+ case SatelliteError.REQUEST_NOT_SUPPORTED:
+ return "SATELLITE_REQUEST_NOT_SUPPORTED";
+ case SatelliteError.NO_RESOURCES:
+ return "SATELLITE_NO_RESOURCES";
+ case SatelliteError.SERVICE_NOT_PROVISIONED:
+ return "SATELLITE_SERVICE_NOT_PROVISIONED";
+ case SatelliteError.SERVICE_PROVISION_IN_PROGRESS:
+ return "SATELLITE_SERVICE_PROVISION_IN_PROGRESS";
+ case SatelliteError.REQUEST_ABORTED:
+ return "SATELLITE_REQUEST_ABORTED";
+ case SatelliteError.SATELLITE_ACCESS_BARRED:
+ return "SATELLITE_ACCESS_BARRED";
+ case SatelliteError.NETWORK_TIMEOUT:
+ return "SATELLITE_NETWORK_TIMEOUT";
+ case SatelliteError.SATELLITE_NOT_REACHABLE:
+ return "SATELLITE_NOT_REACHABLE";
+ case SatelliteError.NOT_AUTHORIZED:
+ return "SATELLITE_NOT_AUTHORIZED";
+ }
+ Log.d(TAG, "Received invalid satellite service error: " + error);
+ return "SATELLITE_SERVICE_ERROR";
+ }
+}
diff --git a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/SatelliteModemState.java b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/SatelliteModemState.java
new file mode 100644
index 0000000..aa0d5b0
--- /dev/null
+++ b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/SatelliteModemState.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.phone.testapps.satellitetestapp;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.telephony.satellite.SatelliteManager;
+import android.telephony.satellite.SatelliteStateCallback;
+import android.util.Log;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.TextView;
+
+/**
+ * Activity related to SatelliteModemState APIs.
+ */
+public class SatelliteModemState extends Activity {
+
+ private static final String TAG = "SatelliteModemState";
+
+ private SatelliteManager mSatelliteManager;
+ private SatelliteStateCallbackTestApp mCallback;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mSatelliteManager = getSystemService(SatelliteManager.class);
+ mCallback = new SatelliteStateCallbackTestApp();
+
+ setContentView(R.layout.activity_SatelliteModemState);
+ findViewById(R.id.registerForSatelliteModemStateChanged)
+ .setOnClickListener(this::registerForSatelliteModemStateChangedApp);
+ findViewById(R.id.unregisterForSatelliteModemStateChanged)
+ .setOnClickListener(this::unregisterForSatelliteModemStateChangedApp);
+ findViewById(R.id.Back).setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ startActivity(new Intent(SatelliteModemState.this, SatelliteTestApp.class));
+ }
+ });
+ }
+
+ protected static class SatelliteStateCallbackTestApp implements SatelliteStateCallback {
+ @Override
+ public void onSatelliteModemStateChanged(int state) {
+ Log.d(TAG, "onSatelliteModemStateChanged in SatelliteTestApp: state=" + state);
+ }
+ }
+
+ private void registerForSatelliteModemStateChangedApp(View view) {
+ int result = mSatelliteManager.registerForSatelliteModemStateChanged(Runnable::run,
+ mCallback);
+ TextView textView = findViewById(R.id.text_id);
+ if (result == 0) {
+ textView.setText("registerForSatelliteModemStateChanged is successful");
+ } else {
+ textView.setText("Status for registerForSatelliteModemStateChanged : "
+ + SatelliteErrorUtils.mapError(result));
+ }
+ }
+
+ private void unregisterForSatelliteModemStateChangedApp(View view) {
+ mSatelliteManager.unregisterForSatelliteModemStateChanged(mCallback);
+ TextView textView = findViewById(R.id.text_id);
+ textView.setText("unregisterForSatelliteModemStateChanged is successful");
+ }
+}
+
diff --git a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/SatelliteTestApp.java b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/SatelliteTestApp.java
new file mode 100644
index 0000000..ed5b75e
--- /dev/null
+++ b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/SatelliteTestApp.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.phone.testapps.satellitetestapp;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.telephony.satellite.stub.SatelliteDatagram;
+import android.util.Log;
+import android.view.View;
+import android.view.View.OnClickListener;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * SatelliteTestApp main activity to navigate to other APIs related to satellite.
+ */
+public class SatelliteTestApp extends Activity {
+
+ private static final String TAG = "SatelliteTestApp";
+ private static TestSatelliteService sSatelliteService;
+ private final Object mSendDatagramLock = new Object();
+
+ private TestSatelliteServiceConnection mSatelliteServiceConn;
+ private List<SatelliteDatagram> mSentSatelliteDatagrams = new ArrayList<>();
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ if (mSatelliteServiceConn == null) {
+ mSatelliteServiceConn = new TestSatelliteServiceConnection();
+ getBaseContext().bindService(new Intent(getBaseContext(),
+ TestSatelliteService.class), mSatelliteServiceConn, Context.BIND_AUTO_CREATE);
+ }
+
+ setContentView(R.layout.activity_SatelliteTestApp);
+ findViewById(R.id.SatelliteControl).setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ Intent intent = new Intent(SatelliteTestApp.this, SatelliteControl.class);
+ startActivity(intent);
+ }
+ });
+ findViewById(R.id.SatelliteTransmissionUpdates).setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ Intent intent = new Intent(SatelliteTestApp.this,
+ SatelliteTransmissionUpdates.class);
+ startActivity(intent);
+ }
+ });
+ findViewById(R.id.Datagram).setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ Intent intent = new Intent(SatelliteTestApp.this, Datagram.class);
+ startActivity(intent);
+ }
+ });
+ findViewById(R.id.Provisioning).setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ Intent intent = new Intent(SatelliteTestApp.this, Provisioning.class);
+ startActivity(intent);
+ }
+ });
+ findViewById(R.id.SatelliteModemState).setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ Intent intent = new Intent(SatelliteTestApp.this, SatelliteModemState.class);
+ startActivity(intent);
+ }
+ });
+ }
+
+ private final ILocalSatelliteListener mSatelliteListener =
+ new ILocalSatelliteListener.Stub() {
+ @Override
+ public void onRemoteServiceConnected() {
+ Log.d(TAG, "onRemoteServiceConnected");
+ }
+
+ @Override
+ public void onStartSendingSatellitePointingInfo() {
+ Log.d(TAG, "onStartSendingSatellitePointingInfo");
+ }
+
+ @Override
+ public void onStopSendingSatellitePointingInfo() {
+ Log.d(TAG, "onStopSendingSatellitePointingInfo");
+ }
+
+ @Override
+ public void onPollPendingSatelliteDatagrams() {
+ Log.d(TAG, "onPollPendingSatelliteDatagrams");
+ }
+
+ @Override
+ public void onSendSatelliteDatagram(
+ SatelliteDatagram datagram, boolean isEmergency) {
+ Log.d(TAG, "onSendSatelliteDatagram");
+ synchronized (mSendDatagramLock) {
+ mSentSatelliteDatagrams.add(datagram);
+ }
+ }
+
+ @Override
+ public void onSatelliteListeningEnabled(boolean enable) {
+ Log.d(TAG, "onSatelliteListeningEnabled");
+ }
+
+ @Override
+ public void onEnableCellularModemWhileSatelliteModeIsOn(boolean enable) {
+ Log.d(TAG, "onEnableCellularModemWhileSatelliteModeIsOn");
+ }
+ };
+
+ private class TestSatelliteServiceConnection implements ServiceConnection {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ Log.d(TAG, "onServiceConnected in SatelliteTestApp");
+ sSatelliteService = ((TestSatelliteService.LocalBinder) service).getService();
+ sSatelliteService.setLocalSatelliteListener(mSatelliteListener);
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ Log.d(TAG, "onServiceDisconnected in SatelliteTestApp");
+ sSatelliteService = null;
+ }
+ }
+
+ public static TestSatelliteService getTestSatelliteService() {
+ return sSatelliteService;
+ }
+}
diff --git a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/SatelliteTransmissionUpdates.java b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/SatelliteTransmissionUpdates.java
new file mode 100644
index 0000000..368f519
--- /dev/null
+++ b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/SatelliteTransmissionUpdates.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.phone.testapps.satellitetestapp;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.telephony.satellite.PointingInfo;
+import android.telephony.satellite.SatelliteManager;
+import android.telephony.satellite.SatelliteTransmissionUpdateCallback;
+import android.util.Log;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.TextView;
+
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Activity related to SatelliteTransmissionUpdates APIs.
+ */
+public class SatelliteTransmissionUpdates extends Activity {
+
+ private static final String TAG = "SatelliteTransmissionUpdates";
+
+ private SatelliteManager mSatelliteManager;
+ private SatelliteTransmissionUpdateCallbackTestApp mCallback;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mSatelliteManager = getSystemService(SatelliteManager.class);
+ mCallback = new SatelliteTransmissionUpdateCallbackTestApp();
+
+ setContentView(R.layout.activity_SatelliteTransmissionUpdates);
+ findViewById(R.id.startSatelliteTransmissionUpdates)
+ .setOnClickListener(this::startSatelliteTransmissionUpdatesApp);
+ findViewById(R.id.stopSatelliteTransmissionUpdates)
+ .setOnClickListener(this::stopSatelliteTransmissionUpdatesApp);
+ findViewById(R.id.Back).setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ startActivity(new Intent(SatelliteTransmissionUpdates.this,
+ SatelliteTestApp.class));
+ }
+ });
+ }
+
+ protected static class SatelliteTransmissionUpdateCallbackTestApp implements
+ SatelliteTransmissionUpdateCallback {
+ @Override
+ public void onSatellitePositionChanged(PointingInfo pointingInfo) {
+ Log.d(TAG, "onSatellitePositionChanged in TestApp: pointingInfo =" + pointingInfo);
+ }
+
+ @Override
+ public void onSendDatagramStateChanged(int state, int sendPendingCount, int errorCode) {
+ Log.d(TAG, "onSendDatagramStateChanged in TestApp: state =" + state
+ + ", sendPendingCount =" + sendPendingCount + ", errorCode=" + errorCode);
+ }
+
+ @Override
+ public void onReceiveDatagramStateChanged(
+ int state, int receivePendingCount, int errorCode) {
+ Log.d(TAG, "onReceiveDatagramStateChanged in TestApp: state=" + state + ", "
+ + "receivePendingCount=" + receivePendingCount + ", errorCode=" + errorCode);
+ }
+ }
+
+ private void startSatelliteTransmissionUpdatesApp(View view) {
+ LinkedBlockingQueue<Integer> error = new LinkedBlockingQueue<>(1);
+ mSatelliteManager.startSatelliteTransmissionUpdates(Runnable::run, error::offer, mCallback);
+ try {
+ Integer value = error.poll(1000, TimeUnit.MILLISECONDS);
+ TextView textView = findViewById(R.id.text_id);
+ if (value == 0) {
+ textView.setText("startSatelliteTransmissionUpdates is Successful");
+ } else {
+ textView.setText("Status for startSatelliteTransmissionUpdates : "
+ + SatelliteErrorUtils.mapError(value));
+ }
+ } catch (InterruptedException e) {
+ Log.e(TAG, "exception caught =" + e);
+ }
+ }
+
+ private void stopSatelliteTransmissionUpdatesApp(View view) {
+ LinkedBlockingQueue<Integer> error = new LinkedBlockingQueue<>(1);
+ mSatelliteManager.stopSatelliteTransmissionUpdates(mCallback, Runnable::run, error::offer);
+ try {
+ Integer value = error.poll(1000, TimeUnit.MILLISECONDS);
+ TextView textView = findViewById(R.id.text_id);
+ if (value == 0) {
+ textView.setText("stopSatelliteTransmissionUpdates is Successful");
+ } else {
+ textView.setText("Status for stopSatelliteTransmissionUpdates : "
+ + SatelliteErrorUtils.mapError(value));
+ }
+ } catch (InterruptedException e) {
+ Log.e(TAG, "exception caught =" + e);
+ }
+ }
+}
diff --git a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/TestSatelliteService.java b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/TestSatelliteService.java
new file mode 100644
index 0000000..5c7f4a2
--- /dev/null
+++ b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/TestSatelliteService.java
@@ -0,0 +1,542 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.phone.testapps.satellitetestapp;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.IBinder;
+import android.telephony.satellite.AntennaDirection;
+import android.telephony.satellite.AntennaPosition;
+import android.telephony.satellite.SatelliteManager;
+import android.telephony.satellite.stub.ISatelliteCapabilitiesConsumer;
+import android.telephony.satellite.stub.ISatelliteListener;
+import android.telephony.satellite.stub.NTRadioTechnology;
+import android.telephony.satellite.stub.PointingInfo;
+import android.telephony.satellite.stub.SatelliteCapabilities;
+import android.telephony.satellite.stub.SatelliteDatagram;
+import android.telephony.satellite.stub.SatelliteError;
+import android.telephony.satellite.stub.SatelliteImplBase;
+import android.telephony.satellite.stub.SatelliteModemState;
+import android.telephony.satellite.stub.SatelliteService;
+import android.util.Log;
+
+import com.android.internal.telephony.IBooleanConsumer;
+import com.android.internal.telephony.IIntegerConsumer;
+import com.android.internal.util.FunctionalUtils;
+import com.android.telephony.Rlog;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.Executor;
+
+/**
+ * Test service for Satellite to verify end to end flow via testapp.
+ */
+public class TestSatelliteService extends SatelliteImplBase {
+ private static final String TAG = "TestSatelliteService";
+
+ // Hardcoded values below
+ private static final int SATELLITE_ALWAYS_VISIBLE = 0;
+ /** SatelliteCapabilities constant indicating that the radio technology is proprietary. */
+ private static final int[] SUPPORTED_RADIO_TECHNOLOGIES =
+ new int[]{NTRadioTechnology.PROPRIETARY};
+ /** SatelliteCapabilities constant indicating that pointing to satellite is required. */
+ private static final boolean POINTING_TO_SATELLITE_REQUIRED = true;
+ /** SatelliteCapabilities constant indicating the maximum number of characters per datagram. */
+ private static final int MAX_BYTES_PER_DATAGRAM = 339;
+ /** SatelliteCapabilities constant keys which are used to fill mAntennaPositionMap. */
+ private static final int[] ANTENNA_POSITION_KEYS = new int[]{
+ SatelliteManager.DISPLAY_MODE_OPENED, SatelliteManager.DISPLAY_MODE_CLOSED};
+ /** SatelliteCapabilities constant values which are used to fill mAntennaPositionMap. */
+ private static final AntennaPosition[] ANTENNA_POSITION_VALUES = new AntennaPosition[] {
+ new AntennaPosition(new AntennaDirection(1, 1, 1),
+ SatelliteManager.DEVICE_HOLD_POSITION_PORTRAIT),
+ new AntennaPosition(new AntennaDirection(2, 2, 2),
+ SatelliteManager.DEVICE_HOLD_POSITION_LANDSCAPE_LEFT)
+ };
+
+ @NonNull
+ private final Map<IBinder, ISatelliteListener> mRemoteListeners = new HashMap<>();
+ @Nullable private ILocalSatelliteListener mLocalListener;
+ private final LocalBinder mBinder = new LocalBinder();
+ @SatelliteError
+ private int mErrorCode = SatelliteError.ERROR_NONE;
+
+ // For local access of this Service.
+ class LocalBinder extends Binder {
+ TestSatelliteService getService() {
+ return TestSatelliteService.this;
+ }
+ }
+
+ private boolean mIsCommunicationAllowedInLocation;
+ private boolean mIsEnabled;
+ private boolean mIsProvisioned;
+ private boolean mIsSupported;
+ private int mModemState;
+ private boolean mIsCellularModemEnabledMode;
+
+ /**
+ * Create TestSatelliteService using the Executor specified for methods being called from
+ * the framework.
+ *
+ * @param executor The executor for the framework to use when executing satellite methods.
+ */
+ public TestSatelliteService(@NonNull Executor executor) {
+ super(executor);
+ mIsCommunicationAllowedInLocation = true;
+ mIsEnabled = false;
+ mIsProvisioned = false;
+ mIsSupported = true;
+ mModemState = SatelliteModemState.SATELLITE_MODEM_STATE_OFF;
+ mIsCellularModemEnabledMode = false;
+ }
+
+ /**
+ * Zero-argument constructor to prevent service binding exception.
+ */
+ public TestSatelliteService() {
+ this(Runnable::run);
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ if (SatelliteService.SERVICE_INTERFACE.equals(intent.getAction())) {
+ logd("Remote service bound");
+ return getBinder();
+ }
+ logd("Local service bound");
+ return mBinder;
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ logd("onCreate");
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ logd("onDestroy");
+ }
+
+ @Override
+ public void setSatelliteListener(@NonNull ISatelliteListener listener) {
+ logd("setSatelliteListener");
+ mRemoteListeners.put(listener.asBinder(), listener);
+ notifyRemoteServiceConnected();
+ }
+
+ @Override
+ public void requestSatelliteListeningEnabled(boolean enabled, int timeout,
+ @NonNull IIntegerConsumer errorCallback) {
+ logd("requestSatelliteListeningEnabled: mErrorCode=" + mErrorCode);
+
+ if (mLocalListener != null) {
+ runWithExecutor(() -> mLocalListener.onSatelliteListeningEnabled(enabled));
+ } else {
+ loge("requestSatelliteListeningEnabled: mLocalListener is null");
+ }
+
+ if (!verifySatelliteModemState(errorCallback)) {
+ return;
+ }
+ if (mErrorCode != SatelliteError.ERROR_NONE) {
+ runWithExecutor(() -> errorCallback.accept(mErrorCode));
+ return;
+ }
+
+ if (enabled) {
+ updateSatelliteModemState(SatelliteModemState.SATELLITE_MODEM_STATE_LISTENING);
+ } else {
+ updateSatelliteModemState(SatelliteModemState.SATELLITE_MODEM_STATE_IDLE);
+ }
+ runWithExecutor(() -> errorCallback.accept(SatelliteError.ERROR_NONE));
+ }
+
+ @Override
+ public void requestSatelliteEnabled(boolean enableSatellite, boolean enableDemoMode,
+ @NonNull IIntegerConsumer errorCallback) {
+ logd("requestSatelliteEnabled: mErrorCode=" + mErrorCode + " enable = " + enableSatellite
+ + "mIsCellularModemEnabledMode = " + mIsCellularModemEnabledMode);
+ if (mErrorCode != SatelliteError.ERROR_NONE) {
+ runWithExecutor(() -> errorCallback.accept(mErrorCode));
+ return;
+ }
+
+ if (enableSatellite) {
+ enableSatellite(errorCallback);
+ } else {
+ mIsCellularModemEnabledMode = false;
+ disableSatellite(errorCallback);
+ }
+ }
+
+ @Override
+ public void enableCellularModemWhileSatelliteModeIsOn(boolean enable,
+ @NonNull IIntegerConsumer errorCallback) {
+ logd("enableCellularModemWhileSatelliteModeIsOn :" + enable + " error Code = " + mErrorCode
+ + "mIsCellularModemEnabledMode = " + mIsCellularModemEnabledMode
+ + " mIsEnabled = " + mIsEnabled);
+ if (mLocalListener != null) {
+ runWithExecutor(() -> mLocalListener
+ .onEnableCellularModemWhileSatelliteModeIsOn(enable));
+ } else {
+ loge("requestSatelliteListeningEnabled: mLocalListener is null");
+ }
+ if (mIsEnabled) {
+ if (enable) {
+ mIsCellularModemEnabledMode = true;
+ disableSatellite(errorCallback);
+ } else {
+ mIsCellularModemEnabledMode = false;
+ enableSatellite(errorCallback);
+ }
+ } else {
+ final int finalError = SatelliteError.INVALID_MODEM_STATE;
+ runWithExecutor(() -> errorCallback.accept(finalError));
+ }
+
+ }
+ private void enableSatellite(@NonNull IIntegerConsumer errorCallback) {
+ mIsEnabled = true;
+ updateSatelliteModemState(SatelliteModemState.SATELLITE_MODEM_STATE_IDLE);
+ runWithExecutor(() -> errorCallback.accept(SatelliteError.ERROR_NONE));
+ }
+
+ private void disableSatellite(@NonNull IIntegerConsumer errorCallback) {
+ mIsEnabled = false;
+ updateSatelliteModemState(SatelliteModemState.SATELLITE_MODEM_STATE_OFF);
+ runWithExecutor(() -> errorCallback.accept(SatelliteError.ERROR_NONE));
+ }
+
+ @Override
+ public void requestIsSatelliteEnabled(@NonNull IIntegerConsumer errorCallback,
+ @NonNull IBooleanConsumer callback) {
+ logd("requestIsSatelliteEnabled: mErrorCode=" + mErrorCode);
+ if (mErrorCode != SatelliteError.ERROR_NONE) {
+ runWithExecutor(() -> errorCallback.accept(mErrorCode));
+ return;
+ }
+ runWithExecutor(() -> callback.accept(mIsEnabled));
+ }
+
+ @Override
+ public void requestIsSatelliteSupported(@NonNull IIntegerConsumer errorCallback,
+ @NonNull IBooleanConsumer callback) {
+ logd("requestIsSatelliteSupported");
+ if (mErrorCode != SatelliteError.ERROR_NONE) {
+ runWithExecutor(() -> errorCallback.accept(mErrorCode));
+ return;
+ }
+ runWithExecutor(() -> callback.accept(mIsSupported));
+ }
+
+ @Override
+ public void requestSatelliteCapabilities(@NonNull IIntegerConsumer errorCallback,
+ @NonNull ISatelliteCapabilitiesConsumer callback) {
+ logd("requestSatelliteCapabilities: mErrorCode=" + mErrorCode);
+ if (mErrorCode != SatelliteError.ERROR_NONE) {
+ runWithExecutor(() -> errorCallback.accept(mErrorCode));
+ return;
+ }
+
+ SatelliteCapabilities capabilities = new SatelliteCapabilities();
+ capabilities.supportedRadioTechnologies = SUPPORTED_RADIO_TECHNOLOGIES;
+ capabilities.isPointingRequired = POINTING_TO_SATELLITE_REQUIRED;
+ capabilities.maxBytesPerOutgoingDatagram = MAX_BYTES_PER_DATAGRAM;
+ capabilities.antennaPositionKeys = ANTENNA_POSITION_KEYS;
+ capabilities.antennaPositionValues = ANTENNA_POSITION_VALUES;
+ runWithExecutor(() -> callback.accept(capabilities));
+ }
+
+ @Override
+ public void startSendingSatellitePointingInfo(@NonNull IIntegerConsumer errorCallback) {
+ logd("startSendingSatellitePointingInfo: mErrorCode=" + mErrorCode);
+ if (!verifySatelliteModemState(errorCallback)) {
+ if (mLocalListener != null) {
+ runWithExecutor(() -> mLocalListener.onStartSendingSatellitePointingInfo());
+ } else {
+ loge("startSendingSatellitePointingInfo: mLocalListener is null");
+ }
+ return;
+ }
+
+ if (mErrorCode != SatelliteError.ERROR_NONE) {
+ runWithExecutor(() -> errorCallback.accept(mErrorCode));
+ } else {
+ runWithExecutor(() -> errorCallback.accept(SatelliteError.ERROR_NONE));
+ }
+
+ if (mLocalListener != null) {
+ runWithExecutor(() -> mLocalListener.onStartSendingSatellitePointingInfo());
+ } else {
+ loge("startSendingSatellitePointingInfo: mLocalListener is null");
+ }
+ }
+
+ @Override
+ public void stopSendingSatellitePointingInfo(@NonNull IIntegerConsumer errorCallback) {
+ logd("stopSendingSatellitePointingInfo: mErrorCode=" + mErrorCode);
+ if (mErrorCode != SatelliteError.ERROR_NONE) {
+ runWithExecutor(() -> errorCallback.accept(mErrorCode));
+ } else {
+ runWithExecutor(() -> errorCallback.accept(SatelliteError.ERROR_NONE));
+ }
+
+ if (mLocalListener != null) {
+ runWithExecutor(() -> mLocalListener.onStopSendingSatellitePointingInfo());
+ } else {
+ loge("stopSendingSatellitePointingInfo: mLocalListener is null");
+ }
+ }
+
+ @Override
+ public void provisionSatelliteService(@NonNull String token, @NonNull byte[] provisionData,
+ @NonNull IIntegerConsumer errorCallback) {
+ logd("provisionSatelliteService: mErrorCode=" + mErrorCode);
+ if (mErrorCode != SatelliteError.ERROR_NONE) {
+ runWithExecutor(() -> errorCallback.accept(mErrorCode));
+ return;
+ }
+ runWithExecutor(() -> errorCallback.accept(SatelliteError.ERROR_NONE));
+ updateSatelliteProvisionState(true);
+ }
+
+ @Override
+ public void deprovisionSatelliteService(@NonNull String token,
+ @NonNull IIntegerConsumer errorCallback) {
+ logd("deprovisionSatelliteService: mErrorCode=" + mErrorCode);
+ if (mErrorCode != SatelliteError.ERROR_NONE) {
+ runWithExecutor(() -> errorCallback.accept(mErrorCode));
+ return;
+ }
+ runWithExecutor(() -> errorCallback.accept(SatelliteError.ERROR_NONE));
+ updateSatelliteProvisionState(false);
+ }
+
+ @Override
+ public void requestIsSatelliteProvisioned(@NonNull IIntegerConsumer errorCallback,
+ @NonNull IBooleanConsumer callback) {
+ logd("requestIsSatelliteProvisioned: mErrorCode=" + mErrorCode);
+ if (mErrorCode != SatelliteError.ERROR_NONE) {
+ runWithExecutor(() -> errorCallback.accept(mErrorCode));
+ return;
+ }
+ runWithExecutor(() -> callback.accept(mIsProvisioned));
+ }
+
+ @Override
+ public void pollPendingSatelliteDatagrams(@NonNull IIntegerConsumer errorCallback) {
+ logd("pollPendingSatelliteDatagrams: mErrorCode=" + mErrorCode);
+ if (mErrorCode != SatelliteError.ERROR_NONE) {
+ runWithExecutor(() -> errorCallback.accept(mErrorCode));
+ } else {
+ runWithExecutor(() -> errorCallback.accept(SatelliteError.ERROR_NONE));
+ }
+
+ if (mLocalListener != null) {
+ runWithExecutor(() -> mLocalListener.onPollPendingSatelliteDatagrams());
+ } else {
+ loge("pollPendingSatelliteDatagrams: mLocalListener is null");
+ }
+ }
+
+ @Override
+ public void sendSatelliteDatagram(@NonNull SatelliteDatagram datagram, boolean isEmergency,
+ @NonNull IIntegerConsumer errorCallback) {
+ logd("sendSatelliteDatagram: mErrorCode=" + mErrorCode);
+ if (mErrorCode != SatelliteError.ERROR_NONE) {
+ runWithExecutor(() -> errorCallback.accept(mErrorCode));
+ } else {
+ runWithExecutor(() -> errorCallback.accept(SatelliteError.ERROR_NONE));
+ }
+
+ if (mLocalListener != null) {
+ runWithExecutor(() -> mLocalListener.onSendSatelliteDatagram(datagram, isEmergency));
+ } else {
+ loge("sendSatelliteDatagram: mLocalListener is null");
+ }
+ }
+
+ @Override
+ public void requestSatelliteModemState(@NonNull IIntegerConsumer errorCallback,
+ @NonNull IIntegerConsumer callback) {
+ logd("requestSatelliteModemState: mErrorCode=" + mErrorCode);
+ if (mErrorCode != SatelliteError.ERROR_NONE) {
+ runWithExecutor(() -> errorCallback.accept(mErrorCode));
+ return;
+ }
+ runWithExecutor(() -> callback.accept(mModemState));
+ }
+
+ @Override
+ public void requestIsSatelliteCommunicationAllowedForCurrentLocation(
+ @NonNull IIntegerConsumer errorCallback, @NonNull IBooleanConsumer callback) {
+ logd("requestIsSatelliteCommunicationAllowedForCurrentLocation: mErrorCode=" + mErrorCode);
+ if (mErrorCode != SatelliteError.ERROR_NONE) {
+ runWithExecutor(() -> errorCallback.accept(mErrorCode));
+ return;
+ }
+
+ if (mIsCommunicationAllowedInLocation) {
+ runWithExecutor(() -> callback.accept(true));
+ } else {
+ runWithExecutor(() -> callback.accept(false));
+ }
+ }
+
+ @Override
+ public void requestTimeForNextSatelliteVisibility(@NonNull IIntegerConsumer errorCallback,
+ @NonNull IIntegerConsumer callback) {
+ logd("requestTimeForNextSatelliteVisibility: mErrorCode=" + mErrorCode);
+ if (mErrorCode != SatelliteError.ERROR_NONE) {
+ runWithExecutor(() -> errorCallback.accept(mErrorCode));
+ return;
+ }
+ runWithExecutor(() -> callback.accept(SATELLITE_ALWAYS_VISIBLE));
+ }
+
+ public void setLocalSatelliteListener(@NonNull ILocalSatelliteListener listener) {
+ logd("setLocalSatelliteListener: listener=" + listener);
+ mLocalListener = listener;
+ }
+
+ public void setErrorCode(@SatelliteError int errorCode) {
+ logd("setErrorCode: errorCode=" + errorCode);
+ mErrorCode = errorCode;
+ }
+
+ public void setSatelliteSupport(boolean supported) {
+ logd("setSatelliteSupport: supported=" + supported);
+ mIsSupported = supported;
+ }
+
+ public void sendOnSatelliteDatagramReceived(SatelliteDatagram datagram, int pendingCount) {
+ logd("sendOnSatelliteDatagramReceived");
+ mRemoteListeners.values().forEach(listener -> runWithExecutor(() ->
+ listener.onSatelliteDatagramReceived(datagram, pendingCount)));
+ }
+
+ public void sendOnPendingDatagrams() {
+ logd("sendOnPendingDatagrams");
+ mRemoteListeners.values().forEach(listener -> runWithExecutor(() ->
+ listener.onPendingDatagrams()));
+ }
+
+ public void sendOnSatellitePositionChanged(PointingInfo pointingInfo) {
+ logd("sendOnSatellitePositionChanged");
+ mRemoteListeners.values().forEach(listener -> runWithExecutor(() ->
+ listener.onSatellitePositionChanged(pointingInfo)));
+ }
+
+ /**
+ * Helper method to verify that the satellite modem is properly configured to receive
+ * requests.
+ *
+ * @param errorCallback The callback to notify of any errors preventing satellite requests.
+ * @return {@code true} if the satellite modem is configured to receive requests and
+ * {@code false} if it is not.
+ */
+ private boolean verifySatelliteModemState(@NonNull IIntegerConsumer errorCallback) {
+ if (!mIsSupported) {
+ runWithExecutor(() -> errorCallback.accept(SatelliteError.REQUEST_NOT_SUPPORTED));
+ return false;
+ }
+ if (!mIsProvisioned) {
+ runWithExecutor(() -> errorCallback.accept(SatelliteError.SERVICE_NOT_PROVISIONED));
+ return false;
+ }
+ if (!mIsEnabled) {
+ runWithExecutor(() -> errorCallback.accept(SatelliteError.INVALID_MODEM_STATE));
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Update the satellite modem state and notify listeners if it changed.
+ *
+ * @param modemState The {@link SatelliteModemState} to update.
+ */
+ private void updateSatelliteModemState(int modemState) {
+ if (modemState == mModemState) {
+ return;
+ }
+ if (mIsCellularModemEnabledMode
+ && modemState == SatelliteModemState.SATELLITE_MODEM_STATE_OFF) {
+ logd("Not updating the Modem state to Off as it is in CellularModemEnabledMode");
+ return;
+ }
+ mRemoteListeners.values().forEach(listener -> runWithExecutor(() ->
+ listener.onSatelliteModemStateChanged(modemState)));
+ mModemState = modemState;
+ }
+
+ /**
+ * Update the satellite provision state and notify listeners if it changed.
+ *
+ * @param isProvisioned {@code true} if the satellite is currently provisioned and
+ * {@code false} if it is not.
+ */
+ private void updateSatelliteProvisionState(boolean isProvisioned) {
+ logd("updateSatelliteProvisionState: isProvisioned=" + isProvisioned
+ + ", mIsProvisioned=" + mIsProvisioned);
+ if (isProvisioned == mIsProvisioned) {
+ return;
+ }
+ mIsProvisioned = isProvisioned;
+ logd("updateSatelliteProvisionState: mRemoteListeners.size=" + mRemoteListeners.size());
+ mRemoteListeners.values().forEach(listener -> runWithExecutor(() ->
+ listener.onSatelliteProvisionStateChanged(mIsProvisioned)));
+ }
+
+ /**
+ * Execute the given runnable using the executor that this service was created with.
+ *
+ * @param r A runnable that can throw an exception.
+ */
+ private void runWithExecutor(@NonNull FunctionalUtils.ThrowingRunnable r) {
+ mExecutor.execute(() -> Binder.withCleanCallingIdentity(r));
+ }
+
+ private void notifyRemoteServiceConnected() {
+ logd("notifyRemoteServiceConnected");
+ runWithExecutor(() -> mLocalListener.onRemoteServiceConnected());
+ }
+
+ /**
+ * Log the message to the radio buffer with {@code DEBUG} priority.
+ *
+ * @param log The message to log.
+ */
+ private static void logd(@NonNull String log) {
+ Rlog.d(TAG, log);
+ }
+
+ /**
+ * Log with error attribute
+ *
+ * @param s is string log
+ */
+ protected void loge(@NonNull String s) {
+ Log.e(TAG, s);
+ }
+}
diff --git a/tests/Android.bp b/tests/Android.bp
index 08cac05..1f15b9b 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -38,6 +38,7 @@
instrumentation_for: "TeleService",
static_libs: [
+ "frameworks-base-testutils",
"androidx.test.core",
"androidx.test.espresso.core",
"androidx.test.ext.junit",
diff --git a/tests/src/com/android/phone/CarrierConfigLoaderTest.java b/tests/src/com/android/phone/CarrierConfigLoaderTest.java
index b6f8ed8..bd2e4f7 100644
--- a/tests/src/com/android/phone/CarrierConfigLoaderTest.java
+++ b/tests/src/com/android/phone/CarrierConfigLoaderTest.java
@@ -40,8 +40,10 @@
import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
+import android.os.PermissionEnforcer;
import android.os.PersistableBundle;
import android.os.UserHandle;
+import android.os.test.FakePermissionEnforcer;
import android.service.carrier.CarrierIdentifier;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager;
@@ -97,10 +99,17 @@
private HandlerThread mHandlerThread;
private TestableLooper mTestableLooper;
+ // The AIDL stub will use PermissionEnforcer to check permission from the caller.
+ private FakePermissionEnforcer mFakePermissionEnforcer = new FakePermissionEnforcer();
+
@Before
public void setUp() throws Exception {
super.setUp();
MockitoAnnotations.initMocks(this);
+ doReturn(Context.PERMISSION_ENFORCER_SERVICE).when(mContext).getSystemServiceName(
+ eq(PermissionEnforcer.class));
+ doReturn(mFakePermissionEnforcer).when(mContext).getSystemService(
+ eq(Context.PERMISSION_ENFORCER_SERVICE));
replaceInstance(SubscriptionManagerService.class, "sInstance", null,
mSubscriptionManagerService);
@@ -142,6 +151,9 @@
@After
public void tearDown() throws Exception {
mContext.revokeAllPermissions();
+ mFakePermissionEnforcer.revoke(android.Manifest.permission.DUMP);
+ mFakePermissionEnforcer.revoke(android.Manifest.permission.MODIFY_PHONE_STATE);
+ mFakePermissionEnforcer.revoke(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
mTestableLooper.destroy();
mHandlerThread.quit();
super.tearDown();
@@ -164,7 +176,7 @@
*/
@Test
public void testUpdateConfigForPhoneId_invalidPhoneId() throws Exception {
- mContext.grantPermission(STUB_PERMISSION_ENABLE_ALL);
+ mFakePermissionEnforcer.grant(android.Manifest.permission.MODIFY_PHONE_STATE);
assertThrows(IllegalArgumentException.class,
() -> mCarrierConfigLoader.updateConfigForPhoneId(
@@ -182,7 +194,7 @@
if (!SubscriptionManager.isValidPhoneId(SubscriptionManager.getPhoneId(DEFAULT_SUB_ID))) {
return;
}
- mContext.grantPermission(STUB_PERMISSION_ENABLE_ALL);
+ mFakePermissionEnforcer.grant(android.Manifest.permission.MODIFY_PHONE_STATE);
doNothing().when(mContext).sendBroadcastAsUser(any(Intent.class), any(UserHandle.class));
// Prepare a cached config to fetch from xml
@@ -215,7 +227,7 @@
if (!SubscriptionManager.isValidPhoneId(SubscriptionManager.getPhoneId(DEFAULT_SUB_ID))) {
return;
}
- mContext.grantPermission(STUB_PERMISSION_ENABLE_ALL);
+ mFakePermissionEnforcer.grant(android.Manifest.permission.MODIFY_PHONE_STATE);
// Prepare to make sure we can save the config into the XML file which used as cache
doReturn(PLATFORM_CARRIER_CONFIG_PACKAGE).when(mTelephonyManager)
@@ -252,7 +264,7 @@
*/
@Test
public void testOverrideConfig_invalidSubId() throws Exception {
- mContext.grantPermission(STUB_PERMISSION_ENABLE_ALL);
+ mFakePermissionEnforcer.grant(android.Manifest.permission.MODIFY_PHONE_STATE);
assertThrows(IllegalArgumentException.class, () -> mCarrierConfigLoader.overrideConfig(
SubscriptionManager.INVALID_SUBSCRIPTION_ID, new PersistableBundle(), false));
@@ -267,7 +279,7 @@
if (!SubscriptionManager.isValidPhoneId(SubscriptionManager.getPhoneId(DEFAULT_SUB_ID))) {
return;
}
- mContext.grantPermission(STUB_PERMISSION_ENABLE_ALL);
+ mFakePermissionEnforcer.grant(android.Manifest.permission.MODIFY_PHONE_STATE);
mCarrierConfigLoader.overrideConfig(DEFAULT_SUB_ID, null /*overrides*/,
false/*persistent*/);
@@ -288,7 +300,7 @@
if (!SubscriptionManager.isValidPhoneId(SubscriptionManager.getPhoneId(DEFAULT_SUB_ID))) {
return;
}
- mContext.grantPermission(STUB_PERMISSION_ENABLE_ALL);
+ mFakePermissionEnforcer.grant(android.Manifest.permission.MODIFY_PHONE_STATE);
PersistableBundle config = getTestConfig();
mCarrierConfigLoader.overrideConfig(DEFAULT_SUB_ID, config /*overrides*/,
@@ -308,7 +320,7 @@
*/
@Test
public void testNotifyConfigChangedForSubId_invalidSubId() throws Exception {
- mContext.grantPermission(STUB_PERMISSION_ENABLE_ALL);
+ mFakePermissionEnforcer.grant(STUB_PERMISSION_ENABLE_ALL);
assertThrows(IllegalArgumentException.class,
() -> mCarrierConfigLoader.notifyConfigChangedForSubId(
@@ -346,7 +358,7 @@
*/
@Test
public void testGetDefaultCarrierServicePackageName_withPermission() {
- mContext.grantPermission(STUB_PERMISSION_ENABLE_ALL);
+ mFakePermissionEnforcer.grant(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
assertThat(mCarrierConfigLoader.getDefaultCarrierServicePackageName())
.isEqualTo(PLATFORM_CARRIER_CONFIG_PACKAGE);
@@ -417,7 +429,7 @@
@Test
public void testMultiSimConfigChanged() throws Exception {
replaceInstance(TelephonyManager.class, "sInstance", null, mTelephonyManager);
- mContext.grantPermission(STUB_PERMISSION_ENABLE_ALL);
+ mFakePermissionEnforcer.grant(android.Manifest.permission.MODIFY_PHONE_STATE);
// Changed from 1 to 2.
doReturn(2).when(mTelephonyManager).getActiveModemCount();