summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Brown <jeffbrown@google.com>2012-11-07 16:02:13 -0800
committerJeff Brown <jeffbrown@google.com>2012-11-07 18:43:32 -0800
commit74da109102864f19b3dcdb30cd1d92c46fb12f2f (patch)
tree831538f1a4c17d10ca06827b8304df62692bf194
parenteb3aa44c10b155f917e8840d55b5bc1de3712ba9 (diff)
downloadframeworks_base-74da109102864f19b3dcdb30cd1d92c46fb12f2f.zip
frameworks_base-74da109102864f19b3dcdb30cd1d92c46fb12f2f.tar.gz
frameworks_base-74da109102864f19b3dcdb30cd1d92c46fb12f2f.tar.bz2
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
-rw-r--r--core/java/android/hardware/display/WifiDisplay.java9
-rw-r--r--media/java/android/media/MediaRouter.java2
-rw-r--r--services/java/com/android/server/display/PersistentDataStore.java25
-rw-r--r--services/java/com/android/server/display/WifiDisplayAdapter.java85
-rw-r--r--services/java/com/android/server/display/WifiDisplayController.java67
5 files changed, 149 insertions, 39 deletions
diff --git a/core/java/android/hardware/display/WifiDisplay.java b/core/java/android/hardware/display/WifiDisplay.java
index 0138b1c..2fd52b8 100644
--- a/core/java/android/hardware/display/WifiDisplay.java
+++ b/core/java/android/hardware/display/WifiDisplay.java
@@ -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.
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index 2a5a16e..8701f36 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -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;
}
}
diff --git a/services/java/com/android/server/display/PersistentDataStore.java b/services/java/com/android/server/display/PersistentDataStore.java
index 3a6e1a6..105c253 100644
--- a/services/java/com/android/server/display/PersistentDataStore.java
+++ b/services/java/com/android/server/display/PersistentDataStore.java
@@ -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) {
diff --git a/services/java/com/android/server/display/WifiDisplayAdapter.java b/services/java/com/android/server/display/WifiDisplayAdapter.java
index 45fff30..c8a44d2 100644
--- a/services/java/com/android/server/display/WifiDisplayAdapter.java
+++ b/services/java/com/android/server/display/WifiDisplayAdapter.java
@@ -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
@@ -496,10 +541,24 @@ 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) {
diff --git a/services/java/com/android/server/display/WifiDisplayController.java b/services/java/com/android/server/display/WifiDisplayController.java
index 39d042f..886e049 100644
--- a/services/java/com/android/server/display/WifiDisplayController.java
+++ b/services/java/com/android/server/display/WifiDisplayController.java
@@ -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();