/**
  * Updates the UI with device data [AR] Called when a peer device is clicked in the [AR] list
  * view, makes a menu appear with a connect/disconnect [AR] button for that peer
  *
  * @param device the device to be displayed
  */
 public void showDetails(WifiP2pDevice device) {
   this.device = device;
   this.getView().setVisibility(View.VISIBLE);
   TextView view = (TextView) mContentView.findViewById(R.id.device_address);
   view.setText(device.deviceAddress);
   view = (TextView) mContentView.findViewById(R.id.device_info);
   view.setText(device.toString());
 }
 private void updateDesiredDevice(WifiP2pDevice device) {
   // Handle the case where the device to which we are connecting or connected
   // may have been renamed or reported different properties in the latest scan.
   final String address = device.deviceAddress;
   if (mDesiredDevice != null && mDesiredDevice.deviceAddress.equals(address)) {
     if (DEBUG) {
       Slog.d(TAG, "updateDesiredDevice: new information " + describeWifiP2pDevice(device));
     }
     mDesiredDevice.update(device);
     if (mAdvertisedDisplay != null && mAdvertisedDisplay.getDeviceAddress().equals(address)) {
       readvertiseDisplay(createWifiDisplay(mDesiredDevice));
     }
   }
 }
  /**
   * This function is called repeatedly after each asynchronous operation until all preconditions
   * for the connection have been satisfied and the connection is established (or not).
   */
  private void updateConnection() {
    // Step 0. Stop scans if necessary to prevent interference while connected.
    // Resume scans later when no longer attempting to connect.
    updateScanState();

    // Step 1. Before we try to connect to a new device, tell the system we
    // have disconnected from the old one.
    if ((mRemoteDisplay != null || mExtRemoteDisplay != null)
        && mConnectedDevice != mDesiredDevice) {
      Slog.i(
          TAG,
          "Stopped listening for RTSP connection on "
              + mRemoteDisplayInterface
              + " from Wifi display: "
              + mConnectedDevice.deviceName);

      if (mRemoteDisplay != null) {
        mRemoteDisplay.dispose();
      } else if (mExtRemoteDisplay != null) {
        ExtendedRemoteDisplayHelper.dispose(mExtRemoteDisplay);
      }

      mExtRemoteDisplay = null;
      mRemoteDisplay = null;
      mRemoteDisplayInterface = null;
      mRemoteDisplayConnected = false;
      mHandler.removeCallbacks(mRtspTimeout);

      mWifiP2pManager.setMiracastMode(WifiP2pManager.MIRACAST_DISABLED);
      unadvertiseDisplay();

      // continue to next step
    }

    // Step 2. Before we try to connect to a new device, disconnect from the old one.
    if (mDisconnectingDevice != null) {
      return; // wait for asynchronous callback
    }
    if (mConnectedDevice != null && mConnectedDevice != mDesiredDevice) {
      Slog.i(TAG, "Disconnecting from Wifi display: " + mConnectedDevice.deviceName);
      mDisconnectingDevice = mConnectedDevice;
      mConnectedDevice = null;
      mConnectedDeviceGroupInfo = null;

      unadvertiseDisplay();

      final WifiP2pDevice oldDevice = mDisconnectingDevice;
      mWifiP2pManager.removeGroup(
          mWifiP2pChannel,
          new ActionListener() {
            @Override
            public void onSuccess() {
              Slog.i(TAG, "Disconnected from Wifi display: " + oldDevice.deviceName);
              next();
            }

            @Override
            public void onFailure(int reason) {
              Slog.i(
                  TAG,
                  "Failed to disconnect from Wifi display: "
                      + oldDevice.deviceName
                      + ", reason="
                      + reason);
              next();
            }

            private void next() {
              if (mDisconnectingDevice == oldDevice) {
                mDisconnectingDevice = null;
                updateConnection();
              }
            }
          });
      return; // wait for asynchronous callback
    }

    // Step 3. Before we try to connect to a new device, stop trying to connect
    // to the old one.
    if (mCancelingDevice != null) {
      return; // wait for asynchronous callback
    }
    if (mConnectingDevice != null && mConnectingDevice != mDesiredDevice) {
      Slog.i(TAG, "Canceling connection to Wifi display: " + mConnectingDevice.deviceName);
      mCancelingDevice = mConnectingDevice;
      mConnectingDevice = null;

      unadvertiseDisplay();
      mHandler.removeCallbacks(mConnectionTimeout);

      final WifiP2pDevice oldDevice = mCancelingDevice;
      mWifiP2pManager.cancelConnect(
          mWifiP2pChannel,
          new ActionListener() {
            @Override
            public void onSuccess() {
              Slog.i(TAG, "Canceled connection to Wifi display: " + oldDevice.deviceName);
              next();
            }

            @Override
            public void onFailure(int reason) {
              Slog.i(
                  TAG,
                  "Failed to cancel connection to Wifi display: "
                      + oldDevice.deviceName
                      + ", reason="
                      + reason);
              next();
            }

            private void next() {
              if (mCancelingDevice == oldDevice) {
                mCancelingDevice = null;
                updateConnection();
              }
            }
          });
      return; // wait for asynchronous callback
    }

    // Step 4. If we wanted to disconnect, or we're updating after starting an
    // autonomous GO, then mission accomplished.
    if (mDesiredDevice == null) {
      if (mWifiDisplayCertMode) {
        mListener.onDisplaySessionInfo(getSessionInfo(mConnectedDeviceGroupInfo, 0));
      }
      unadvertiseDisplay();
      return; // done
    }

    // Step 5. Try to connect.
    if (mConnectedDevice == null && mConnectingDevice == null) {
      Slog.i(TAG, "Connecting to Wifi display: " + mDesiredDevice.deviceName);

      mConnectingDevice = mDesiredDevice;
      WifiP2pConfig config = new WifiP2pConfig();
      WpsInfo wps = new WpsInfo();
      if (mWifiDisplayWpsConfig != WpsInfo.INVALID) {
        wps.setup = mWifiDisplayWpsConfig;
      } else if (mConnectingDevice.wpsPbcSupported()) {
        wps.setup = WpsInfo.PBC;
      } else if (mConnectingDevice.wpsDisplaySupported()) {
        // We do keypad if peer does display
        wps.setup = WpsInfo.KEYPAD;
      } else {
        wps.setup = WpsInfo.DISPLAY;
      }
      config.wps = wps;
      config.deviceAddress = mConnectingDevice.deviceAddress;
      // Helps with STA & P2P concurrency
      config.groupOwnerIntent = WifiP2pConfig.MIN_GROUP_OWNER_INTENT;

      WifiDisplay display = createWifiDisplay(mConnectingDevice);
      advertiseDisplay(display, null, 0, 0, 0);

      final WifiP2pDevice newDevice = mDesiredDevice;
      mWifiP2pManager.connect(
          mWifiP2pChannel,
          config,
          new ActionListener() {
            @Override
            public void onSuccess() {
              // The connection may not yet be established.  We still need to wait
              // for WIFI_P2P_CONNECTION_CHANGED_ACTION.  However, we might never
              // get that broadcast, so we register a timeout.
              Slog.i(TAG, "Initiated connection to Wifi display: " + newDevice.deviceName);

              mHandler.postDelayed(mConnectionTimeout, CONNECTION_TIMEOUT_SECONDS * 1000);
            }

            @Override
            public void onFailure(int reason) {
              if (mConnectingDevice == newDevice) {
                Slog.i(
                    TAG,
                    "Failed to initiate connection to Wifi display: "
                        + newDevice.deviceName
                        + ", reason="
                        + reason);
                mConnectingDevice = null;
                handleConnectionFailure(false);
              }
            }
          });
      return; // wait for asynchronous callback
    }

    // Step 6. Listen for incoming RTSP connection.
    if (mConnectedDevice != null && mRemoteDisplay == null && mExtRemoteDisplay == null) {
      Inet4Address addr = getInterfaceAddress(mConnectedDeviceGroupInfo);
      if (addr == null) {
        Slog.i(
            TAG,
            "Failed to get local interface address for communicating "
                + "with Wifi display: "
                + mConnectedDevice.deviceName);
        handleConnectionFailure(false);
        return; // done
      }

      mWifiP2pManager.setMiracastMode(WifiP2pManager.MIRACAST_SOURCE);

      final WifiP2pDevice oldDevice = mConnectedDevice;
      final int port = getPortNumber(mConnectedDevice);
      final String iface = addr.getHostAddress() + ":" + port;
      mRemoteDisplayInterface = iface;

      Slog.i(
          TAG,
          "Listening for RTSP connection on "
              + iface
              + " from Wifi display: "
              + mConnectedDevice.deviceName);

      RemoteDisplay.Listener listener =
          new RemoteDisplay.Listener() {
            @Override
            public void onDisplayConnected(
                Surface surface, int width, int height, int flags, int session) {
              if (mConnectedDevice == oldDevice && !mRemoteDisplayConnected) {
                Slog.i(
                    TAG,
                    "Opened RTSP connection with Wifi display: " + mConnectedDevice.deviceName);
                mRemoteDisplayConnected = true;
                mHandler.removeCallbacks(mRtspTimeout);

                if (mWifiDisplayCertMode) {
                  mListener.onDisplaySessionInfo(
                      getSessionInfo(mConnectedDeviceGroupInfo, session));
                }

                final WifiDisplay display = createWifiDisplay(mConnectedDevice);
                advertiseDisplay(display, surface, width, height, flags);
              }
            }

            @Override
            public void onDisplayDisconnected() {
              if (mConnectedDevice == oldDevice) {
                Slog.i(
                    TAG,
                    "Closed RTSP connection with Wifi display: " + mConnectedDevice.deviceName);
                mHandler.removeCallbacks(mRtspTimeout);
                disconnect();
              }
            }

            @Override
            public void onDisplayError(int error) {
              if (mConnectedDevice == oldDevice) {
                Slog.i(
                    TAG,
                    "Lost RTSP connection with Wifi display due to error "
                        + error
                        + ": "
                        + mConnectedDevice.deviceName);
                mHandler.removeCallbacks(mRtspTimeout);
                handleConnectionFailure(false);
              }
            }
          };
      if (ExtendedRemoteDisplayHelper.isAvailable()) {
        mExtRemoteDisplay = ExtendedRemoteDisplayHelper.listen(iface, listener, mHandler, mContext);
      } else {
        mRemoteDisplay =
            RemoteDisplay.listen(iface, listener, mHandler, mContext.getOpPackageName());
      }

      // Use extended timeout value for certification, as some tests require user inputs
      int rtspTimeout =
          mWifiDisplayCertMode ? RTSP_TIMEOUT_SECONDS_CERT_MODE : RTSP_TIMEOUT_SECONDS;

      mHandler.postDelayed(mRtspTimeout, rtspTimeout * 1000);
    }
  }
 private static String describeWifiP2pDevice(WifiP2pDevice device) {
   return device != null ? device.toString().replace('\n', ',') : "null";
 }