# Class Vpn

java.lang.Object
com.codename1.vpn.profile.Vpn

public final class Vpn extends Object

Installing and controlling a VPN configuration the operating system runs for you.

    if (Vpn.isSupported()) {
        Vpn.install(new VpnProfile("vpn.example.com")
                .usernamePassword("alice", secret))
           .ready(v -> Vpn.start());
    }

##### The tunnel is the platform's, not this app's

Nothing here carries packets. The configuration is handed to the operating system, which runs its own IKEv2 or IPsec client; the app starts it, stops it and watches it. Implementing the tunnel itself is a different and much larger undertaking -- see the note in the `com.codename1.vpn` package documentation -- and this API stays useful around it either way, for the install, the status and the control.

##### The user may be asked, and the app cannot skip the asking

`install(VpnProfile)` shows a system prompt when the platform wants consent, and there is no way around it: a declined prompt fails with `VpnError.USER_DECLINED`, which is an ordinary outcome and not an error to report to the user again.

It is NOT a prompt on every install. Android asks once and remembers, so replacing a profile in an app the user has already approved provisions and answers with nothing shown -- the port takes that path whenever `provisionVpnProfile` returns no consent intent. An app that treated each install as a fresh checkpoint, or that told the user a dialog was coming, was wrong in that case.

So: be ready for the prompt, and do not depend on it appearing.

##### One configuration per app

Both platforms give an app a single managed configuration, so `install(VpnProfile)` replaces whatever was there rather than adding to it.

- ## Method Summary

  Modifier and Type
  Method
  Description
  `static void`
  `addStatusListener(VpnStatusListener l)`
  Adds a status listener.
  `static int`
  `getCapabilities()`
  The `VpnBridge.CAPABILITY_*` mask this platform supports.
  `static VpnStatus`
  `getStatus()`
  Where the tunnel is right now.
  `static AsyncResource<Boolean>`
  `install(VpnProfile profile)`
  Installs or replaces this app's configuration, after asking the user.
  `static boolean`
  `isSupported()`
  Whether this platform can install and control a VPN configuration.
  `static AsyncResource<VpnProfile>`
  `load()`
  Reads back the installed configuration, resolving null when none is installed.
  `static AsyncResource<Boolean>`
  `remove()`
  Removes this app's configuration.
  `static void`
  `removeStatusListener(VpnStatusListener l)`
  Removes a status listener, stopping delivery when the last one goes.
  `static AsyncResource<Boolean>`
  `start()`
  Brings the tunnel up.
  `static AsyncResource<Boolean>`
  `stop()`
  Takes the tunnel down.

  ### Methods inherited from class Object

  `clone, equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

- ## Method Details

  - ### isSupported

    public static boolean isSupported()

    Whether this platform can install and control a VPN configuration.

    False on Android below API 30, and on every port with no VPN machinery. Note this is a different question from whether a VPN is running -- `com.codename1.io.NetworkManager#isVPNActive()` answers that one, on many more platforms and with no entitlement.

  - ### getCapabilities

    public static int getCapabilities()
    The `VpnBridge.CAPABILITY_*` mask this platform supports.

  - ### getStatus

    public static VpnStatus getStatus()
    Where the tunnel is right now.

  - ### install

    public static AsyncResource<Boolean> install(VpnProfile profile)
    Installs or replaces this app's configuration, after asking the user.

  - ### remove

    public static AsyncResource<Boolean> remove()
    Removes this app's configuration.

  - ### load

    public static AsyncResource<VpnProfile> load()

    Reads back the installed configuration, resolving null when none is installed.

    The result never carries the password -- the platform keeps it. See `VpnProfile.getPassword()`.

    ###### On Android this is this app's RECORD, not a platform read

    `VpnManager` provisions, deletes, starts and stops; it has no call that hands a profile back. So the description here is the one this app kept when it installed, and it can outlive the real thing -- the user removing the VPN in Settings, or app data restored onto a device that never had it, both leave the record saying a profile exists.

    It corrects itself the first time the platform contradicts it: a start or a stop that comes back "nothing is provisioned" drops the record and moves the status to NOT_CONFIGURED. An app that must be certain should `start()` rather than trust a description, and watch the status. iOS reads the real configuration and has no such gap.

  - ### start

    public static AsyncResource<Boolean> start()
    Brings the tunnel up.

  - ### stop

    public static AsyncResource<Boolean> stop()
    Takes the tunnel down.

  - ### addStatusListener

    public static void addStatusListener(VpnStatusListener l)
    Adds a status listener. Arrives on the EDT.

  - ### removeStatusListener

    public static void removeStatusListener(VpnStatusListener l)
    Removes a status listener, stopping delivery when the last one goes.