Support Wifi display devices that rename themselves.
Some Wifi display devices like to rename themselves after a connection completes (or at other times). Make sure to update the name of the display when we detect that it changed in our scan results. This problem is somewhat complicated by the fact that we remember the display name persistently, so we need to update our list of remembered displays too. Improve the state machine to avoid redundant attempts to disconnect or cancel connection. Bug: 7478895 Change-Id: I35a9e2c6a8deadbe892dacd5e3b4a5a2b12d6cf0
This commit is contained in:
@@ -107,6 +107,15 @@ public final class WifiDisplay implements Parcelable {
|
||||
&& Objects.equal(mDeviceAlias, other.mDeviceAlias);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the other display is not null and has the same address as this one.
|
||||
* Can be used to perform identity comparisons on displays ignoring properties
|
||||
* that might change during a connection such as the name or alias.
|
||||
*/
|
||||
public boolean hasSameAddress(WifiDisplay other) {
|
||||
return other != null && mDeviceAddress.equals(other.mDeviceAddress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
// The address on its own should be sufficiently unique for hashing purposes.
|
||||
|
||||
@@ -862,7 +862,7 @@ public class MediaRouter {
|
||||
private static WifiDisplay findMatchingDisplay(WifiDisplay d, WifiDisplay[] displays) {
|
||||
for (int i = 0; i < displays.length; i++) {
|
||||
final WifiDisplay other = displays[i];
|
||||
if (d.getDeviceAddress().equals(other.getDeviceAddress())) {
|
||||
if (d.hasSameAddress(other)) {
|
||||
return other;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,6 +81,15 @@ final class PersistentDataStore {
|
||||
}
|
||||
}
|
||||
|
||||
public WifiDisplay getRememberedWifiDisplay(String deviceAddress) {
|
||||
loadIfNeeded();
|
||||
int index = findRememberedWifiDisplay(deviceAddress);
|
||||
if (index >= 0) {
|
||||
return mRememberedWifiDisplays.get(index);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public WifiDisplay[] getRememberedWifiDisplays() {
|
||||
loadIfNeeded();
|
||||
return mRememberedWifiDisplays.toArray(new WifiDisplay[mRememberedWifiDisplays.size()]);
|
||||
@@ -137,22 +146,6 @@ final class PersistentDataStore {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean renameWifiDisplay(String deviceAddress, String alias) {
|
||||
int index = findRememberedWifiDisplay(deviceAddress);
|
||||
if (index >= 0) {
|
||||
WifiDisplay display = mRememberedWifiDisplays.get(index);
|
||||
if (Objects.equal(display.getDeviceAlias(), alias)) {
|
||||
return false; // already has this alias
|
||||
}
|
||||
WifiDisplay renamedDisplay = new WifiDisplay(deviceAddress,
|
||||
display.getDeviceName(), alias);
|
||||
mRememberedWifiDisplays.set(index, renamedDisplay);
|
||||
setDirty();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean forgetWifiDisplay(String deviceAddress) {
|
||||
int index = findRememberedWifiDisplay(deviceAddress);
|
||||
if (index >= 0) {
|
||||
|
||||
@@ -45,6 +45,8 @@ import android.view.Surface;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Arrays;
|
||||
|
||||
import libcore.util.Objects;
|
||||
|
||||
/**
|
||||
* Connects to Wifi displays that implement the Miracast protocol.
|
||||
* <p>
|
||||
@@ -224,16 +226,18 @@ final class WifiDisplayAdapter extends DisplayAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
if (mPersistentDataStore.renameWifiDisplay(address, alias)) {
|
||||
mPersistentDataStore.saveIfNeeded();
|
||||
updateRememberedDisplaysLocked();
|
||||
scheduleStatusChangedBroadcastLocked();
|
||||
WifiDisplay display = mPersistentDataStore.getRememberedWifiDisplay(address);
|
||||
if (display != null && !Objects.equal(display.getDeviceAlias(), alias)) {
|
||||
display = new WifiDisplay(address, display.getDeviceName(), alias);
|
||||
if (mPersistentDataStore.rememberWifiDisplay(display)) {
|
||||
mPersistentDataStore.saveIfNeeded();
|
||||
updateRememberedDisplaysLocked();
|
||||
scheduleStatusChangedBroadcastLocked();
|
||||
}
|
||||
}
|
||||
|
||||
if (mActiveDisplay != null && mActiveDisplay.getDeviceAddress().equals(address)
|
||||
&& mDisplayDevice != null) {
|
||||
mDisplayDevice.setNameLocked(mActiveDisplay.getFriendlyDisplayName());
|
||||
sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_CHANGED);
|
||||
if (mActiveDisplay != null && mActiveDisplay.getDeviceAddress().equals(address)) {
|
||||
renameDisplayDeviceLocked(mActiveDisplay.getFriendlyDisplayName());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -272,9 +276,42 @@ final class WifiDisplayAdapter extends DisplayAdapter {
|
||||
mAvailableDisplays = mPersistentDataStore.applyWifiDisplayAliases(mAvailableDisplays);
|
||||
}
|
||||
|
||||
private void handleConnectLocked(WifiDisplay display,
|
||||
private void fixRememberedDisplayNamesFromAvailableDisplaysLocked() {
|
||||
// It may happen that a display name has changed since it was remembered.
|
||||
// Consult the list of available displays and update the name if needed.
|
||||
// We don't do anything special for the active display here. The display
|
||||
// controller will send a separate event when it needs to be updates.
|
||||
boolean changed = false;
|
||||
for (int i = 0; i < mRememberedDisplays.length; i++) {
|
||||
WifiDisplay rememberedDisplay = mRememberedDisplays[i];
|
||||
WifiDisplay availableDisplay = findAvailableDisplayLocked(
|
||||
rememberedDisplay.getDeviceAddress());
|
||||
if (availableDisplay != null && !rememberedDisplay.equals(availableDisplay)) {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "fixRememberedDisplayNamesFromAvailableDisplaysLocked: "
|
||||
+ "updating remembered display to " + availableDisplay);
|
||||
}
|
||||
mRememberedDisplays[i] = availableDisplay;
|
||||
changed |= mPersistentDataStore.rememberWifiDisplay(availableDisplay);
|
||||
}
|
||||
}
|
||||
if (changed) {
|
||||
mPersistentDataStore.saveIfNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
private WifiDisplay findAvailableDisplayLocked(String address) {
|
||||
for (WifiDisplay display : mAvailableDisplays) {
|
||||
if (display.getDeviceAddress().equals(address)) {
|
||||
return display;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void addDisplayDeviceLocked(WifiDisplay display,
|
||||
Surface surface, int width, int height, int flags) {
|
||||
handleDisconnectLocked();
|
||||
removeDisplayDeviceLocked();
|
||||
|
||||
if (mPersistentDataStore.rememberWifiDisplay(display)) {
|
||||
mPersistentDataStore.saveIfNeeded();
|
||||
@@ -303,7 +340,7 @@ final class WifiDisplayAdapter extends DisplayAdapter {
|
||||
scheduleUpdateNotificationLocked();
|
||||
}
|
||||
|
||||
private void handleDisconnectLocked() {
|
||||
private void removeDisplayDeviceLocked() {
|
||||
if (mDisplayDevice != null) {
|
||||
mDisplayDevice.clearSurfaceLocked();
|
||||
sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_REMOVED);
|
||||
@@ -313,6 +350,13 @@ final class WifiDisplayAdapter extends DisplayAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
private void renameDisplayDeviceLocked(String name) {
|
||||
if (mDisplayDevice != null && !mDisplayDevice.getNameLocked().equals(name)) {
|
||||
mDisplayDevice.setNameLocked(name);
|
||||
sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
private void scheduleStatusChangedBroadcastLocked() {
|
||||
mCurrentStatus = null;
|
||||
if (!mPendingStatusChangeBroadcast) {
|
||||
@@ -446,6 +490,7 @@ final class WifiDisplayAdapter extends DisplayAdapter {
|
||||
|| !Arrays.equals(mAvailableDisplays, availableDisplays)) {
|
||||
mScanState = WifiDisplayStatus.SCAN_STATE_NOT_SCANNING;
|
||||
mAvailableDisplays = availableDisplays;
|
||||
fixRememberedDisplayNamesFromAvailableDisplaysLocked();
|
||||
scheduleStatusChangedBroadcastLocked();
|
||||
}
|
||||
}
|
||||
@@ -483,7 +528,7 @@ final class WifiDisplayAdapter extends DisplayAdapter {
|
||||
int width, int height, int flags) {
|
||||
synchronized (getSyncRoot()) {
|
||||
display = mPersistentDataStore.applyWifiDisplayAlias(display);
|
||||
handleConnectLocked(display, surface, width, height, flags);
|
||||
addDisplayDeviceLocked(display, surface, width, height, flags);
|
||||
|
||||
if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_CONNECTED
|
||||
|| mActiveDisplay == null
|
||||
@@ -495,11 +540,25 @@ final class WifiDisplayAdapter extends DisplayAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisplayChanged(WifiDisplay display) {
|
||||
synchronized (getSyncRoot()) {
|
||||
display = mPersistentDataStore.applyWifiDisplayAlias(display);
|
||||
if (mActiveDisplay != null
|
||||
&& mActiveDisplay.hasSameAddress(display)
|
||||
&& !mActiveDisplay.equals(display)) {
|
||||
mActiveDisplay = display;
|
||||
renameDisplayDeviceLocked(display.getFriendlyDisplayName());
|
||||
scheduleStatusChangedBroadcastLocked();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisplayDisconnected() {
|
||||
// Stop listening.
|
||||
synchronized (getSyncRoot()) {
|
||||
handleDisconnectLocked();
|
||||
removeDisplayDeviceLocked();
|
||||
|
||||
if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED
|
||||
|| mActiveDisplay != null) {
|
||||
|
||||
@@ -120,6 +120,12 @@ final class WifiDisplayController implements DumpUtils.Dump {
|
||||
// or are not trying to connect.
|
||||
private WifiP2pDevice mConnectingDevice;
|
||||
|
||||
// The device from which we are currently disconnecting.
|
||||
private WifiP2pDevice mDisconnectingDevice;
|
||||
|
||||
// The device to which we were previously trying to connect and are now canceling.
|
||||
private WifiP2pDevice mCancelingDevice;
|
||||
|
||||
// The device to which we are currently connected, which means we have an active P2P group.
|
||||
private WifiP2pDevice mConnectedDevice;
|
||||
|
||||
@@ -186,6 +192,7 @@ final class WifiDisplayController implements DumpUtils.Dump {
|
||||
updateWfdEnableState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(PrintWriter pw) {
|
||||
pw.println("mWifiDisplayOnSetting=" + mWifiDisplayOnSetting);
|
||||
pw.println("mWifiP2pEnabled=" + mWifiP2pEnabled);
|
||||
@@ -196,6 +203,8 @@ final class WifiDisplayController implements DumpUtils.Dump {
|
||||
pw.println("mDiscoverPeersRetriesLeft=" + mDiscoverPeersRetriesLeft);
|
||||
pw.println("mDesiredDevice=" + describeWifiP2pDevice(mDesiredDevice));
|
||||
pw.println("mConnectingDisplay=" + describeWifiP2pDevice(mConnectingDevice));
|
||||
pw.println("mDisconnectingDisplay=" + describeWifiP2pDevice(mDisconnectingDevice));
|
||||
pw.println("mCancelingDisplay=" + describeWifiP2pDevice(mCancelingDevice));
|
||||
pw.println("mConnectedDevice=" + describeWifiP2pDevice(mConnectedDevice));
|
||||
pw.println("mConnectionRetriesLeft=" + mConnectionRetriesLeft);
|
||||
pw.println("mRemoteDisplay=" + mRemoteDisplay);
|
||||
@@ -384,7 +393,9 @@ final class WifiDisplayController implements DumpUtils.Dump {
|
||||
final int count = mAvailableWifiDisplayPeers.size();
|
||||
final WifiDisplay[] displays = WifiDisplay.CREATOR.newArray(count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
displays[i] = createWifiDisplay(mAvailableWifiDisplayPeers.get(i));
|
||||
WifiP2pDevice device = mAvailableWifiDisplayPeers.get(i);
|
||||
displays[i] = createWifiDisplay(device);
|
||||
updateDesiredDevice(device);
|
||||
}
|
||||
|
||||
mHandler.post(new Runnable() {
|
||||
@@ -395,6 +406,23 @@ final class WifiDisplayController implements DumpUtils.Dump {
|
||||
});
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void connect(final WifiP2pDevice device) {
|
||||
if (mDesiredDevice != null
|
||||
&& !mDesiredDevice.deviceAddress.equals(device.deviceAddress)) {
|
||||
@@ -459,12 +487,17 @@ final class WifiDisplayController implements DumpUtils.Dump {
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
unadvertiseDisplay();
|
||||
|
||||
final WifiP2pDevice oldDevice = mConnectedDevice;
|
||||
final WifiP2pDevice oldDevice = mDisconnectingDevice;
|
||||
mWifiP2pManager.removeGroup(mWifiP2pChannel, new ActionListener() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
@@ -480,8 +513,8 @@ final class WifiDisplayController implements DumpUtils.Dump {
|
||||
}
|
||||
|
||||
private void next() {
|
||||
if (mConnectedDevice == oldDevice) {
|
||||
mConnectedDevice = null;
|
||||
if (mDisconnectingDevice == oldDevice) {
|
||||
mDisconnectingDevice = null;
|
||||
updateConnection();
|
||||
}
|
||||
}
|
||||
@@ -491,13 +524,18 @@ final class WifiDisplayController implements DumpUtils.Dump {
|
||||
|
||||
// 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 = mConnectingDevice;
|
||||
final WifiP2pDevice oldDevice = mCancelingDevice;
|
||||
mWifiP2pManager.cancelConnect(mWifiP2pChannel, new ActionListener() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
@@ -513,8 +551,8 @@ final class WifiDisplayController implements DumpUtils.Dump {
|
||||
}
|
||||
|
||||
private void next() {
|
||||
if (mConnectingDevice == oldDevice) {
|
||||
mConnectingDevice = null;
|
||||
if (mCancelingDevice == oldDevice) {
|
||||
mCancelingDevice = null;
|
||||
updateConnection();
|
||||
}
|
||||
}
|
||||
@@ -763,13 +801,17 @@ final class WifiDisplayController implements DumpUtils.Dump {
|
||||
public void run() {
|
||||
if (oldSurface != null && surface != oldSurface) {
|
||||
mListener.onDisplayDisconnected();
|
||||
} else if (oldDisplay != null && !Objects.equal(display, oldDisplay)) {
|
||||
} else if (oldDisplay != null && !oldDisplay.hasSameAddress(display)) {
|
||||
mListener.onDisplayConnectionFailed();
|
||||
}
|
||||
|
||||
if (display != null) {
|
||||
if (!Objects.equal(display, oldDisplay)) {
|
||||
if (!display.hasSameAddress(oldDisplay)) {
|
||||
mListener.onDisplayConnecting(display);
|
||||
} else if (!display.equals(oldDisplay)) {
|
||||
// The address is the same but some other property such as the
|
||||
// name must have changed.
|
||||
mListener.onDisplayChanged(display);
|
||||
}
|
||||
if (surface != null && surface != oldSurface) {
|
||||
mListener.onDisplayConnected(display, surface, width, height, flags);
|
||||
@@ -784,6 +826,12 @@ final class WifiDisplayController implements DumpUtils.Dump {
|
||||
advertiseDisplay(null, null, 0, 0, 0);
|
||||
}
|
||||
|
||||
private void readvertiseDisplay(WifiDisplay display) {
|
||||
advertiseDisplay(display, mAdvertisedDisplaySurface,
|
||||
mAdvertisedDisplayWidth, mAdvertisedDisplayHeight,
|
||||
mAdvertisedDisplayFlags);
|
||||
}
|
||||
|
||||
private static Inet4Address getInterfaceAddress(WifiP2pGroup info) {
|
||||
NetworkInterface iface;
|
||||
try {
|
||||
@@ -885,6 +933,7 @@ final class WifiDisplayController implements DumpUtils.Dump {
|
||||
|
||||
void onDisplayConnecting(WifiDisplay display);
|
||||
void onDisplayConnectionFailed();
|
||||
void onDisplayChanged(WifiDisplay display);
|
||||
void onDisplayConnected(WifiDisplay display,
|
||||
Surface surface, int width, int height, int flags);
|
||||
void onDisplayDisconnected();
|
||||
|
||||
Reference in New Issue
Block a user