Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f8f0eddd authored by Jeff Brown's avatar Jeff Brown
Browse files

Improve reporting of wifi connection state.

We should only report that the wifi display is connected
after the RTSP connection has been fully established.

Change-Id: Ifc6bc5d5cebd42d551026885b31cbc74b7ece2b1
parent 59c53c62
Loading
Loading
Loading
Loading
+22 −104
Original line number Diff line number Diff line
@@ -27,7 +27,6 @@ import android.hardware.display.WifiDisplayStatus;
import android.media.RemoteDisplay;
import android.os.Handler;
import android.os.IBinder;
import android.util.Slog;
import android.view.Surface;

import java.io.PrintWriter;
@@ -50,8 +49,8 @@ import java.util.Arrays;
final class WifiDisplayAdapter extends DisplayAdapter {
    private static final String TAG = "WifiDisplayAdapter";

    private WifiDisplayHandle mDisplayHandle;
    private WifiDisplayController mDisplayController;
    private WifiDisplayDevice mDisplayDevice;

    private WifiDisplayStatus mCurrentStatus;
    private boolean mEnabled;
@@ -71,13 +70,6 @@ final class WifiDisplayAdapter extends DisplayAdapter {
    public void dumpLocked(PrintWriter pw) {
        super.dumpLocked(pw);

        if (mDisplayHandle == null) {
            pw.println("mDisplayHandle=null");
        } else {
            pw.println("mDisplayHandle:");
            mDisplayHandle.dumpLocked(pw);
        }

        pw.println("mCurrentStatus=" + getWifiDisplayStatusLocked());
        pw.println("mEnabled=" + mEnabled);
        pw.println("mScanState=" + mScanState);
@@ -151,16 +143,29 @@ final class WifiDisplayAdapter extends DisplayAdapter {
        return mCurrentStatus;
    }

    private void handleConnectLocked(WifiDisplay display, String iface) {
    private void handleConnectLocked(WifiDisplay display,
            Surface surface, int width, int height, int flags) {
        handleDisconnectLocked();

        mDisplayHandle = new WifiDisplayHandle(display.getDeviceName(), iface);
        int deviceFlags = 0;
        if ((flags & RemoteDisplay.DISPLAY_FLAG_SECURE) != 0) {
            deviceFlags |= DisplayDeviceInfo.FLAG_SECURE;
        }

        float refreshRate = 60.0f; // TODO: get this for real

        String name = display.getDeviceName();
        IBinder displayToken = Surface.createDisplay(name);
        mDisplayDevice = new WifiDisplayDevice(displayToken, name, width, height,
                refreshRate, deviceFlags, surface);
        sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_ADDED);
    }

    private void handleDisconnectLocked() {
        if (mDisplayHandle != null) {
            mDisplayHandle.disposeLocked();
            mDisplayHandle = null;
        if (mDisplayDevice != null) {
            mDisplayDevice.clearSurfaceLocked();
            sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_REMOVED);
            mDisplayDevice = null;
        }
    }

@@ -258,9 +263,10 @@ final class WifiDisplayAdapter extends DisplayAdapter {
        }

        @Override
        public void onDisplayConnected(WifiDisplay display, String iface) {
        public void onDisplayConnected(WifiDisplay display, Surface surface,
                int width, int height, int flags) {
            synchronized (getSyncRoot()) {
                handleConnectLocked(display, iface);
                handleConnectLocked(display, surface, width, height, flags);

                if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_CONNECTED
                        || mActiveDisplay == null
@@ -337,92 +343,4 @@ final class WifiDisplayAdapter extends DisplayAdapter {
            return mInfo;
        }
    }

    private final class WifiDisplayHandle implements RemoteDisplay.Listener {
        private final String mName;
        private final String mIface;
        private final RemoteDisplay mRemoteDisplay;

        private WifiDisplayDevice mDevice;
        private int mLastError;

        public WifiDisplayHandle(String name, String iface) {
            mName = name;
            mIface = iface;
            mRemoteDisplay = RemoteDisplay.listen(iface, this, getHandler());

            Slog.i(TAG, "Listening for Wifi display connections on " + iface
                    + " from " + mName);
        }

        public void disposeLocked() {
            Slog.i(TAG, "Stopped listening for Wifi display connections on " + mIface
                    + " from " + mName);

            removeDisplayLocked();
            mRemoteDisplay.dispose();
        }

        public void dumpLocked(PrintWriter pw) {
            pw.println("  " + mName + ": " + (mDevice != null ? "connected" : "disconnected"));
            pw.println("    mIface=" + mIface);
            pw.println("    mLastError=" + mLastError);
        }

        // Called on the handler thread.
        @Override
        public void onDisplayConnected(Surface surface, int width, int height, int flags) {
            synchronized (getSyncRoot()) {
                mLastError = 0;
                removeDisplayLocked();
                addDisplayLocked(surface, width, height, flags);

                Slog.i(TAG, "Wifi display connected: " + mName);
            }
        }

        // Called on the handler thread.
        @Override
        public void onDisplayDisconnected() {
            synchronized (getSyncRoot()) {
                mLastError = 0;
                removeDisplayLocked();

                Slog.i(TAG, "Wifi display disconnected: " + mName);
            }
        }

        // Called on the handler thread.
        @Override
        public void onDisplayError(int error) {
            synchronized (getSyncRoot()) {
                mLastError = error;
                removeDisplayLocked();

                Slog.i(TAG, "Wifi display disconnected due to error " + error + ": " + mName);
            }
        }

        private void addDisplayLocked(Surface surface, int width, int height, int flags) {
            int deviceFlags = 0;
            if ((flags & RemoteDisplay.DISPLAY_FLAG_SECURE) != 0) {
                deviceFlags |= DisplayDeviceInfo.FLAG_SECURE;
            }

            float refreshRate = 60.0f; // TODO: get this for real

            IBinder displayToken = Surface.createDisplay(mName);
            mDevice = new WifiDisplayDevice(displayToken, mName, width, height,
                    refreshRate, deviceFlags, surface);
            sendDisplayDeviceEventLocked(mDevice, DISPLAY_DEVICE_EVENT_ADDED);
        }

        private void removeDisplayLocked() {
            if (mDevice != null) {
                mDevice.clearSurfaceLocked();
                sendDisplayDeviceEventLocked(mDevice, DISPLAY_DEVICE_EVENT_REMOVED);
                mDevice = null;
            }
        }
    }
}
+100 −26
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.display.WifiDisplay;
import android.media.RemoteDisplay;
import android.net.NetworkInfo;
import android.net.wifi.p2p.WifiP2pConfig;
import android.net.wifi.p2p.WifiP2pDevice;
@@ -36,6 +37,7 @@ import android.net.wifi.p2p.WifiP2pManager.GroupInfoListener;
import android.net.wifi.p2p.WifiP2pManager.PeerListListener;
import android.os.Handler;
import android.util.Slog;
import android.view.Surface;

import java.io.PrintWriter;
import java.net.Inet4Address;
@@ -64,6 +66,7 @@ final class WifiDisplayController implements DumpUtils.Dump {
    private static final int DEFAULT_CONTROL_PORT = 7236;
    private static final int MAX_THROUGHPUT = 50;
    private static final int CONNECTION_TIMEOUT_SECONDS = 30;
    private static final int RTSP_TIMEOUT_SECONDS = 15;

    private static final int DISCOVER_PEERS_MAX_RETRIES = 10;
    private static final int DISCOVER_PEERS_RETRY_DELAY_MILLIS = 500;
@@ -104,12 +107,19 @@ final class WifiDisplayController implements DumpUtils.Dump {
    // The group info obtained after connecting.
    private WifiP2pGroup mConnectedDeviceGroupInfo;

    // The device that we announced to the rest of the system.
    private WifiP2pDevice mPublishedDevice;

    // Number of connection retries remaining.
    private int mConnectionRetriesLeft;

    // The remote display that is listening on the connection.
    // Created after the Wifi P2P network is connected.
    private RemoteDisplay mRemoteDisplay;

    // The remote display interface.
    private String mRemoteDisplayInterface;

    // True if RTSP has connected.
    private boolean mRemoteDisplayConnected;

    public WifiDisplayController(Context context, Handler handler, Listener listener) {
        mContext = context;
        mHandler = handler;
@@ -135,8 +145,10 @@ final class WifiDisplayController implements DumpUtils.Dump {
        pw.println("mDesiredDevice=" + describeWifiP2pDevice(mDesiredDevice));
        pw.println("mConnectingDisplay=" + describeWifiP2pDevice(mConnectingDevice));
        pw.println("mConnectedDevice=" + describeWifiP2pDevice(mConnectedDevice));
        pw.println("mPublishedDevice=" + describeWifiP2pDevice(mPublishedDevice));
        pw.println("mConnectionRetriesLeft=" + mConnectionRetriesLeft);
        pw.println("mRemoteDisplay=" + mRemoteDisplay);
        pw.println("mRemoteDisplayInterface=" + mRemoteDisplayInterface);
        pw.println("mRemoteDisplayConnected=" + mRemoteDisplayConnected);

        pw.println("mKnownWifiDisplayPeers: size=" + mKnownWifiDisplayPeers.size());
        for (WifiP2pDevice device : mKnownWifiDisplayPeers) {
@@ -341,7 +353,7 @@ final class WifiDisplayController implements DumpUtils.Dump {
    }

    private void retryConnection() {
        if (mDesiredDevice != null && mPublishedDevice != mDesiredDevice
        if (mDesiredDevice != null && mConnectedDevice != mDesiredDevice
                && mConnectionRetriesLeft > 0) {
            mConnectionRetriesLeft -= 1;
            Slog.i(TAG, "Retrying Wifi display connection.  Retries left: "
@@ -363,14 +375,22 @@ final class WifiDisplayController implements DumpUtils.Dump {
    private void updateConnection() {
        // Step 1. Before we try to connect to a new device, tell the system we
        // have disconnected from the old one.
        if (mPublishedDevice != null && mPublishedDevice != mDesiredDevice) {
        if (mRemoteDisplay != null && mConnectedDevice != mDesiredDevice) {
            Slog.i(TAG, "Stopped listening for RTSP connection on " + mRemoteDisplayInterface
                    + " from Wifi display: " + mConnectedDevice.deviceName);

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

            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    mListener.onDisplayDisconnected();
                }
            });
            mPublishedDevice = null;

            // continue to next step
        }
@@ -471,9 +491,9 @@ final class WifiDisplayController implements DumpUtils.Dump {

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

        // Step 6. Publish the new connection.
        if (mConnectedDevice != null && mPublishedDevice == null) {
        // Step 6. Listen for incoming connections.
        if (mConnectedDevice != null && mRemoteDisplay == null) {
            Inet4Address addr = getInterfaceAddress(mConnectedDeviceGroupInfo);
            if (addr == null) {
                Slog.i(TAG, "Failed to get local interface address for communicating "
@@ -492,20 +512,60 @@ final class WifiDisplayController implements DumpUtils.Dump {
                return; // done
            }

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

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

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

                        final WifiDisplay display = createWifiDisplay(mConnectedDevice);
                        mHandler.post(new Runnable() {
                            @Override
                            public void run() {
                    mListener.onDisplayConnected(display, iface);
                                mListener.onDisplayConnected(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);
                    }
                }
            }, mHandler);

            mHandler.postDelayed(mRtspTimeout, RTSP_TIMEOUT_SECONDS * 1000);
        }
    }

    private void handleStateChanged(boolean enabled) {
        if (mWifiP2pEnabled != enabled) {
            mWifiP2pEnabled = enabled;
@@ -591,8 +651,20 @@ final class WifiDisplayController implements DumpUtils.Dump {
        }
    };

    private final Runnable mRtspTimeout = new Runnable() {
        @Override
        public void run() {
            if (mConnectedDevice != null
                    && mRemoteDisplay != null && !mRemoteDisplayConnected) {
                Slog.i(TAG, "Timed out waiting for Wifi display RTSP connection after "
                        + RTSP_TIMEOUT_SECONDS + " seconds: "
                        + mConnectedDevice.deviceName);
                handleConnectionFailure(true);
            }
        }
    };

    private void handleConnectionFailure(boolean timeoutOccurred) {
        if (mDesiredDevice != null) {
        Slog.i(TAG, "Wifi display connection failed!");

        mHandler.post(new Runnable() {
@@ -602,6 +674,7 @@ final class WifiDisplayController implements DumpUtils.Dump {
            }
        });

        if (mDesiredDevice != null) {
            if (mConnectionRetriesLeft > 0) {
                mHandler.postDelayed(new Runnable() {
                    @Override
@@ -714,7 +787,8 @@ final class WifiDisplayController implements DumpUtils.Dump {

        void onDisplayConnecting(WifiDisplay display);
        void onDisplayConnectionFailed();
        void onDisplayConnected(WifiDisplay display, String iface);
        void onDisplayConnected(WifiDisplay display,
                Surface surface, int width, int height, int flags);
        void onDisplayDisconnected();
    }
}