Develop for constrained satellite networks

Satellite networks will someday be robust enough to function as normal networks and work seamlessly with all app use cases; but for now, data on these networks is a scarce resource. A satellite-based network with constraints on data use is called a constrained satellite network.

Due to these constraints, Android apps don't use these networks by default. If you want your app to operate on constrained satellite networks, you must identify your app as optimized for satellite data usage and adapt your app's use cases to conserve resources when connected to a constrained satellite network.

Adapt your app's use cases

All you have to do to allow your app to access constrained satellite networks is opt in, but you might need to make further changes to optimize your app's behavior to use limited network resources responsibly. Here are some things to consider when you optimize for constrained data usage:

  • Decide whether your app is suitable for use on constrained networks. Some apps aren't a good fit for data-constrained networks under any circumstances. For example, video streaming apps might choose not to use satellite networks at all, though they could still identify the presence of a satellite network and inform the user that they won't function on the existing limited network.
  • Identify specific use cases to limit or modify. Some of your app's features might be better suited to limited data conditions than others. For example, sending text messages would work well, but attempting to upload HD video would likely result in a poor user experience. This is similar to the way many apps change behavior when roaming.
  • Adapt the way your app uses network resources. Constrained networks work best when apps perform network operations in bursts and spend most of the time not using the network. Avoid creating constant or chatty network traffic. For example, push-to-talk audio is much better suited to constrained network conditions than real-time audio calls.

There are also specific changes you need to make if your app uses complex networking logic or Firebase Cloud Messaging.

Self-identify as optimized for constrained networks

To identify your app as optimized for constrained networks and opt into using them, update your app manifest file with a <meta-data> element as follows:

<meta-data android:name="android.telephony.PROPERTY_SATELLITE_DATA_OPTIMIZED"
          android:value="PACKAGE_NAME" />

This element allows your app to use a constrained satellite network when it's the only network available. It also notifies the system that your app is optimized for constrained networks, aiding in user discovery by listing it among the satellite-enabled apps in the settings app.

Change behavior under constrained data conditions

If you need to change your app's behavior when using a constrained network, or if your app has pre-existing logic that uses ConnectivityManager to manage network use, you'll need to make some changes to your network flow.

Detect constrained data conditions

The NetworkCapabilities object used for network requests includes a NET_CAPABILITY_NOT_BANDWIDTH_CONSTRAINED bit that is set by default on all networks and removed on networks that are bandwidth-constrained. You can determine whether a network is bandwidth-constrained by checking whether or not it has the NET_CAPABILITY_NOT_BANDWIDTH_CONSTRAINED capability.

Work with constrained networks

NetworkRequest objects also include the NET_CAPABILITY_NOT_BANDWIDTH_CONSTRAINED capability by default. Remove this capability to indicate that constrained networks are acceptable.

When you detect that you've connected to a constrained network, you can adapt your app's features as necessary:

Kotlin

val HandlerThread = HandlerThread("SatelliteNetworkMonitor"
handlerThread.start()
val handler = Handler(handlerThread.getLooper())

// Make the network request.
val request = NetworkRequest.Builder()
    .addCapability(NET_CAPABILITY_INTERNET
    .removeCapability(NET_CAPABILITY_NOT_BANDWIDTH_CONSTRAINED)
    .build()

// Register for the callback.
val callback = NetworkCallback() {
    override fun onCapabilitiesChanged(net: Network, nc: NetWorkCapabilities) {
        updateAppUseCases(net, nc)
    }

    fun updateAppUseCases(net: Network, nc: NetworkCapabilities) {
        if (!nc.hasCapability(NET_CAPABILITY_NOT_BANDWIDTH_CONSTRAINED) ||
             nc.hasTransport(NetworkCapabilities.TRANSPORT_SATELLITE)) {
            // Adapt to constrained network or disable heavy data usage features.
            ...
        } else {
            // Revert to unconstrained behavior.
            ...
        }
    }
}
// Where cm is your ConnectivityManager object:
cm.registerBestMatchingNetworkCallback(request, callback, handler)

Java

HandlerThread handlerThread = new HandlerThread("SatelliteNetworkMonitor");
handlerThread.start();
Handler handler = new Handler(handlerThread.getLooper());

// Make the network request.
NetworkRequest request = new NetworkRequest.Builder()
    .addCapability(NET_CAPABILITY_INTERNET)
    .removeCapability(NET_CAPABILITY_NOT_BANDWIDTH_CONSTRAINED)
    .build();

// Register for the callback.
NetworkCallback callback = new NetworkCallback() {
    @Override
    public void onCapabilitiesChanged(Network net, NetworkCapabilities nc) {
        updateAppUsecases(net, nc);
    }
    private void updateAppUsecases(Network net, NetworkCapabilities nc) {
        if (!nc.hasCapability(NET_CAPABILITY_NOT_BANDWIDTH_CONSTRAINED) || nc.hasTransport(NetworkCapabilities.TRANSPORT_SATELLITE)) {
            // Adapt to constrained network or disable heavy data usage features.
            ...
        } else {
            // Revert to unconstrained behavior.
            ...
        }
    }
};
// Where cm is your ConnectivityManager object:
cm.registerBestMatchingNetworkCallback(request, callback, handler);

Receive FCM messages on constrained networks

If your app uses Firebase Cloud Messaging (FCM) to receive messages from an app server, you can indicate that a specific message should be delivered even on constrained networks by including the bandwidth_constrained_ok flag when passing the message to the FCM server:

{
  "message":{
    "token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
    "notification":{
      "title":"Portugal vs. Denmark",
      "body":"great match!"
    }
    "android": {
       "bandwidth_constrained_ok": true
    }
  }
}

If a message doesn't include this flag, then the FCM server only delivers it when the device is connected through an unconstrained network.