summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/hardware/display/DisplayManager.java21
-rw-r--r--core/java/android/hardware/display/DisplayManagerGlobal.java33
-rw-r--r--core/java/android/hardware/display/IDisplayManager.aidl23
-rw-r--r--media/java/android/media/MediaRouter.java61
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java10
-rw-r--r--services/java/com/android/server/display/DisplayManagerService.java82
-rw-r--r--services/java/com/android/server/display/WifiDisplayAdapter.java50
-rw-r--r--services/java/com/android/server/display/WifiDisplayController.java163
8 files changed, 318 insertions, 125 deletions
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index d5208d97bd41..093e0e9270ff 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -297,16 +297,31 @@ public final class DisplayManager {
}
/**
- * Initiates a fresh scan of availble Wifi displays.
+ * Starts scanning for available Wifi displays.
* The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast.
* <p>
+ * Calls to this method nest and must be matched by an equal number of calls to
+ * {@link #stopWifiDisplayScan()}.
+ * </p><p>
+ * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}.
+ * </p>
+ *
+ * @hide
+ */
+ public void startWifiDisplayScan() {
+ mGlobal.startWifiDisplayScan();
+ }
+
+ /**
+ * Stops scanning for available Wifi displays.
+ * <p>
* Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}.
* </p>
*
* @hide
*/
- public void scanWifiDisplays() {
- mGlobal.scanWifiDisplays();
+ public void stopWifiDisplayScan() {
+ mGlobal.stopWifiDisplayScan();
}
/**
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 936a0867fd83..34174301ac8e 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -72,6 +72,8 @@ public final class DisplayManagerGlobal {
private final SparseArray<DisplayInfo> mDisplayInfoCache = new SparseArray<DisplayInfo>();
private int[] mDisplayIdCache;
+ private int mWifiDisplayScanNestCount;
+
private DisplayManagerGlobal(IDisplayManager dm) {
mDm = dm;
}
@@ -267,11 +269,32 @@ public final class DisplayManagerGlobal {
}
}
- public void scanWifiDisplays() {
- try {
- mDm.scanWifiDisplays();
- } catch (RemoteException ex) {
- Log.e(TAG, "Failed to scan for Wifi displays.", ex);
+ public void startWifiDisplayScan() {
+ synchronized (mLock) {
+ if (mWifiDisplayScanNestCount++ == 0) {
+ registerCallbackIfNeededLocked();
+ try {
+ mDm.startWifiDisplayScan();
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Failed to scan for Wifi displays.", ex);
+ }
+ }
+ }
+ }
+
+ public void stopWifiDisplayScan() {
+ synchronized (mLock) {
+ if (--mWifiDisplayScanNestCount == 0) {
+ try {
+ mDm.stopWifiDisplayScan();
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Failed to scan for Wifi displays.", ex);
+ }
+ } else if (mWifiDisplayScanNestCount < 0) {
+ Log.wtf(TAG, "Wifi display scan nest count became negative: "
+ + mWifiDisplayScanNestCount);
+ mWifiDisplayScanNestCount = 0;
+ }
}
}
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index 6b2c887639bd..68eb13fb6d58 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -29,11 +29,14 @@ interface IDisplayManager {
void registerCallback(in IDisplayManagerCallback callback);
- // No permissions required.
- void scanWifiDisplays();
+ // Requires CONFIGURE_WIFI_DISPLAY permission.
+ // The process must have previously registered a callback.
+ void startWifiDisplayScan();
- // Requires CONFIGURE_WIFI_DISPLAY permission to connect to an unknown device.
- // No permissions required to connect to a known device.
+ // Requires CONFIGURE_WIFI_DISPLAY permission.
+ void stopWifiDisplayScan();
+
+ // Requires CONFIGURE_WIFI_DISPLAY permission.
void connectWifiDisplay(String address);
// No permissions required.
@@ -45,6 +48,12 @@ interface IDisplayManager {
// Requires CONFIGURE_WIFI_DISPLAY permission.
void forgetWifiDisplay(String address);
+ // Requires CONFIGURE_WIFI_DISPLAY permission.
+ void pauseWifiDisplay();
+
+ // Requires CONFIGURE_WIFI_DISPLAY permission.
+ void resumeWifiDisplay();
+
// No permissions required.
WifiDisplayStatus getWifiDisplayStatus();
@@ -55,10 +64,4 @@ interface IDisplayManager {
// No permissions required but must be same Uid as the creator.
void releaseVirtualDisplay(in IBinder token);
-
- // Requires CONFIGURE_WIFI_DISPLAY permission.
- void pauseWifiDisplay();
-
- // Requires CONFIGURE_WIFI_DISPLAY permission.
- void resumeWifiDisplay();
}
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index 3f1851d74c34..de202278c40b 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -61,9 +61,6 @@ public class MediaRouter {
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
static class Static implements DisplayManager.DisplayListener {
- // Time between wifi display scans when actively scanning in milliseconds.
- private static final int WIFI_DISPLAY_SCAN_INTERVAL = 10000;
-
final Context mAppContext;
final Resources mResources;
final IAudioService mAudioService;
@@ -87,6 +84,7 @@ public class MediaRouter {
final boolean mCanConfigureWifiDisplays;
boolean mActivelyScanningWifiDisplays;
+ String mPreviousActiveWifiDisplayAddress;
int mDiscoveryRequestRouteTypes;
boolean mDiscoverRequestActiveScan;
@@ -106,16 +104,6 @@ public class MediaRouter {
}
};
- final Runnable mScanWifiDisplays = new Runnable() {
- @Override
- public void run() {
- if (mActivelyScanningWifiDisplays) {
- mDisplayService.scanWifiDisplays();
- mHandler.postDelayed(this, WIFI_DISPLAY_SCAN_INTERVAL);
- }
- }
- };
-
Static(Context appContext) {
mAppContext = appContext;
mResources = Resources.getSystem();
@@ -279,15 +267,24 @@ public class MediaRouter {
}
// Update wifi display scanning.
- if (activeScanWifiDisplay && mCanConfigureWifiDisplays) {
- if (!mActivelyScanningWifiDisplays) {
- mActivelyScanningWifiDisplays = true;
- mHandler.post(mScanWifiDisplays);
+ // TODO: All of this should be managed by the media router service.
+ if (mCanConfigureWifiDisplays) {
+ if (mSelectedRoute != null
+ && mSelectedRoute.matchesTypes(ROUTE_TYPE_REMOTE_DISPLAY)) {
+ // Don't scan while already connected to a remote display since
+ // it may interfere with the ongoing transmission.
+ activeScanWifiDisplay = false;
}
- } else {
- if (mActivelyScanningWifiDisplays) {
- mActivelyScanningWifiDisplays = false;
- mHandler.removeCallbacks(mScanWifiDisplays);
+ if (activeScanWifiDisplay) {
+ if (!mActivelyScanningWifiDisplays) {
+ mActivelyScanningWifiDisplays = true;
+ mDisplayService.startWifiDisplayScan();
+ }
+ } else {
+ if (mActivelyScanningWifiDisplays) {
+ mActivelyScanningWifiDisplays = false;
+ mDisplayService.stopWifiDisplayScan();
+ }
}
}
@@ -945,6 +942,9 @@ public class MediaRouter {
}
dispatchRouteSelected(types & route.getSupportedTypes(), route);
}
+
+ // The behavior of active scans may depend on the currently selected route.
+ sStatic.updateDiscoveryRequest();
}
static void selectDefaultRouteStatic() {
@@ -1291,10 +1291,8 @@ public class MediaRouter {
}
static void updateWifiDisplayStatus(WifiDisplayStatus status) {
- boolean wantScan = false;
WifiDisplay[] displays;
WifiDisplay activeDisplay;
-
if (status.getFeatureState() == WifiDisplayStatus.FEATURE_STATE_ON) {
displays = status.getDisplays();
activeDisplay = status.getActiveDisplay();
@@ -1314,6 +1312,8 @@ public class MediaRouter {
displays = WifiDisplay.EMPTY_ARRAY;
activeDisplay = null;
}
+ String activeDisplayAddress = activeDisplay != null ?
+ activeDisplay.getDeviceAddress() : null;
// Add or update routes.
for (int i = 0; i < displays.length; i++) {
@@ -1323,9 +1323,11 @@ public class MediaRouter {
if (route == null) {
route = makeWifiDisplayRoute(d, status);
addRouteStatic(route);
- wantScan = true;
} else {
- updateWifiDisplayRoute(route, d, status);
+ String address = d.getDeviceAddress();
+ boolean disconnected = !address.equals(activeDisplayAddress)
+ && address.equals(sStatic.mPreviousActiveWifiDisplayAddress);
+ updateWifiDisplayRoute(route, d, status, disconnected);
}
if (d.equals(activeDisplay)) {
selectRouteStatic(route.getSupportedTypes(), route, false);
@@ -1343,6 +1345,10 @@ public class MediaRouter {
}
}
}
+
+ // Remember the current active wifi display address so that we can infer disconnections.
+ // TODO: This hack will go away once all of this is moved into the media router service.
+ sStatic.mPreviousActiveWifiDisplayAddress = activeDisplayAddress;
}
private static boolean shouldShowWifiDisplay(WifiDisplay d, WifiDisplay activeDisplay) {
@@ -1400,7 +1406,8 @@ public class MediaRouter {
}
private static void updateWifiDisplayRoute(
- RouteInfo route, WifiDisplay display, WifiDisplayStatus wfdStatus) {
+ RouteInfo route, WifiDisplay display, WifiDisplayStatus wfdStatus,
+ boolean disconnected) {
boolean changed = false;
final String newName = display.getFriendlyDisplayName();
if (!route.getName().equals(newName)) {
@@ -1418,7 +1425,7 @@ public class MediaRouter {
dispatchRouteChanged(route);
}
- if (!enabled && route.isSelected()) {
+ if ((!enabled || disconnected) && route.isSelected()) {
// Oops, no longer available. Reselect the default.
selectDefaultRouteStatic();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
index e1a20ecedfd4..42201c5a2d98 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
@@ -692,14 +692,8 @@ class QuickSettingsModel implements BluetoothStateChangeCallback,
} else {
connectedRoute = null;
connecting = false;
- final int count = mMediaRouter.getRouteCount();
- for (int i = 0; i < count; i++) {
- MediaRouter.RouteInfo route = mMediaRouter.getRouteAt(i);
- if (route.matchesTypes(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY)) {
- enabled = true;
- break;
- }
- }
+ enabled = mMediaRouter.isRouteAvailable(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY,
+ MediaRouter.AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE);
}
mRemoteDisplayState.enabled = enabled;
diff --git a/services/java/com/android/server/display/DisplayManagerService.java b/services/java/com/android/server/display/DisplayManagerService.java
index 02f26b375a2a..bcb677fa455f 100644
--- a/services/java/com/android/server/display/DisplayManagerService.java
+++ b/services/java/com/android/server/display/DisplayManagerService.java
@@ -35,6 +35,7 @@ import android.os.RemoteException;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.text.TextUtils;
+import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.view.Display;
@@ -173,6 +174,9 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
// The Wifi display adapter, or null if not registered.
private WifiDisplayAdapter mWifiDisplayAdapter;
+ // The number of active wifi display scan requests.
+ private int mWifiDisplayScanRequestCount;
+
// The virtual display adapter, or null if not registered.
private VirtualDisplayAdapter mVirtualDisplayAdapter;
@@ -458,29 +462,81 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
}
}
- private void onCallbackDied(int pid) {
+ private void onCallbackDied(CallbackRecord record) {
synchronized (mSyncRoot) {
- mCallbacks.remove(pid);
+ mCallbacks.remove(record.mPid);
+ stopWifiDisplayScanLocked(record);
}
}
@Override // Binder call
- public void scanWifiDisplays() {
+ public void startWifiDisplayScan() {
mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
- "Permission required to scan wifi displays");
+ "Permission required to start wifi display scans");
+ final int callingPid = Binder.getCallingPid();
final long token = Binder.clearCallingIdentity();
try {
synchronized (mSyncRoot) {
+ CallbackRecord record = mCallbacks.get(callingPid);
+ if (record == null) {
+ throw new IllegalStateException("The calling process has not "
+ + "registered an IDisplayManagerCallback.");
+ }
+ startWifiDisplayScanLocked(record);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ private void startWifiDisplayScanLocked(CallbackRecord record) {
+ if (!record.mWifiDisplayScanRequested) {
+ record.mWifiDisplayScanRequested = true;
+ if (mWifiDisplayScanRequestCount++ == 0) {
if (mWifiDisplayAdapter != null) {
- mWifiDisplayAdapter.requestScanLocked();
+ mWifiDisplayAdapter.requestStartScanLocked();
}
}
+ }
+ }
+
+ @Override // Binder call
+ public void stopWifiDisplayScan() {
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
+ "Permission required to stop wifi display scans");
+
+ final int callingPid = Binder.getCallingPid();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mSyncRoot) {
+ CallbackRecord record = mCallbacks.get(callingPid);
+ if (record == null) {
+ throw new IllegalStateException("The calling process has not "
+ + "registered an IDisplayManagerCallback.");
+ }
+ stopWifiDisplayScanLocked(record);
+ }
} finally {
Binder.restoreCallingIdentity(token);
}
}
+ private void stopWifiDisplayScanLocked(CallbackRecord record) {
+ if (record.mWifiDisplayScanRequested) {
+ record.mWifiDisplayScanRequested = false;
+ if (--mWifiDisplayScanRequestCount == 0) {
+ if (mWifiDisplayAdapter != null) {
+ mWifiDisplayAdapter.requestStopScanLocked();
+ }
+ } else if (mWifiDisplayScanRequestCount < 0) {
+ Log.wtf(TAG, "mWifiDisplayScanRequestCount became negative: "
+ + mWifiDisplayScanRequestCount);
+ mWifiDisplayScanRequestCount = 0;
+ }
+ }
+ }
+
@Override // Binder call
public void connectWifiDisplay(String address) {
if (address == null) {
@@ -1107,6 +1163,7 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
pw.println(" mDefaultViewport=" + mDefaultViewport);
pw.println(" mExternalTouchViewport=" + mExternalTouchViewport);
pw.println(" mSingleDisplayDemoMode=" + mSingleDisplayDemoMode);
+ pw.println(" mWifiDisplayScanRequestCount=" + mWifiDisplayScanRequestCount);
IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
ipw.increaseIndent();
@@ -1134,6 +1191,15 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
pw.println(" Display " + displayId + ":");
display.dumpLocked(ipw);
}
+
+ final int callbackCount = mCallbacks.size();
+ pw.println();
+ pw.println("Callbacks: size=" + callbackCount);
+ for (int i = 0; i < callbackCount; i++) {
+ CallbackRecord callback = mCallbacks.valueAt(i);
+ pw.println(" " + i + ": mPid=" + callback.mPid
+ + ", mWifiDisplayScanRequested=" + callback.mWifiDisplayScanRequested);
+ }
}
}
@@ -1234,9 +1300,11 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
}
private final class CallbackRecord implements DeathRecipient {
- private final int mPid;
+ public final int mPid;
private final IDisplayManagerCallback mCallback;
+ public boolean mWifiDisplayScanRequested;
+
public CallbackRecord(int pid, IDisplayManagerCallback callback) {
mPid = pid;
mCallback = callback;
@@ -1247,7 +1315,7 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
if (DEBUG) {
Slog.d(TAG, "Display listener for pid " + mPid + " died.");
}
- onCallbackDied(mPid);
+ onCallbackDied(this);
}
public void notifyDisplayEventAsync(int displayId, int event) {
diff --git a/services/java/com/android/server/display/WifiDisplayAdapter.java b/services/java/com/android/server/display/WifiDisplayAdapter.java
index fdef0398078d..cd57941bcc3e 100644
--- a/services/java/com/android/server/display/WifiDisplayAdapter.java
+++ b/services/java/com/android/server/display/WifiDisplayAdapter.java
@@ -127,7 +127,7 @@ final class WifiDisplayAdapter extends DisplayAdapter {
pw.println("mPendingStatusChangeBroadcast=" + mPendingStatusChangeBroadcast);
pw.println("mPendingNotificationUpdate=" + mPendingNotificationUpdate);
pw.println("mSupportsProtectedBuffers=" + mSupportsProtectedBuffers);
-
+
// Try to dump the controller state.
if (mDisplayController == null) {
pw.println("mDisplayController=null");
@@ -157,43 +157,49 @@ final class WifiDisplayAdapter extends DisplayAdapter {
});
}
- public void requestScanLocked() {
+ public void requestStartScanLocked() {
if (DEBUG) {
- Slog.d(TAG, "requestScanLocked");
+ Slog.d(TAG, "requestStartScanLocked");
}
getHandler().post(new Runnable() {
@Override
public void run() {
if (mDisplayController != null) {
- mDisplayController.requestScan();
+ mDisplayController.requestStartScan();
}
}
});
}
- public void requestConnectLocked(final String address) {
+ public void requestStopScanLocked() {
if (DEBUG) {
- Slog.d(TAG, "requestConnectLocked: address=" + address);
+ Slog.d(TAG, "requestStopScanLocked");
}
getHandler().post(new Runnable() {
@Override
public void run() {
if (mDisplayController != null) {
- mDisplayController.requestConnect(address);
+ mDisplayController.requestStopScan();
}
}
});
}
- private boolean isRememberedDisplayLocked(String address) {
- for (WifiDisplay display : mRememberedDisplays) {
- if (display.getDeviceAddress().equals(address)) {
- return true;
- }
+ public void requestConnectLocked(final String address) {
+ if (DEBUG) {
+ Slog.d(TAG, "requestConnectLocked: address=" + address);
}
- return false;
+
+ getHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ if (mDisplayController != null) {
+ mDisplayController.requestConnect(address);
+ }
+ }
+ });
}
public void requestPauseLocked() {
@@ -552,20 +558,20 @@ final class WifiDisplayAdapter extends DisplayAdapter {
}
@Override
- public void onScanFinished(WifiDisplay[] availableDisplays) {
+ public void onScanResults(WifiDisplay[] availableDisplays) {
synchronized (getSyncRoot()) {
availableDisplays = mPersistentDataStore.applyWifiDisplayAliases(
availableDisplays);
- // check if any of the available displays changed canConnect status
boolean changed = !Arrays.equals(mAvailableDisplays, availableDisplays);
+
+ // Check whether any of the available displays changed canConnect status.
for (int i = 0; !changed && i<availableDisplays.length; i++) {
changed = availableDisplays[i].canConnect()
!= mAvailableDisplays[i].canConnect();
}
- if (mScanState != WifiDisplayStatus.SCAN_STATE_NOT_SCANNING || changed) {
- mScanState = WifiDisplayStatus.SCAN_STATE_NOT_SCANNING;
+ if (changed) {
mAvailableDisplays = availableDisplays;
fixRememberedDisplayNamesFromAvailableDisplaysLocked();
updateDisplaysLocked();
@@ -575,6 +581,16 @@ final class WifiDisplayAdapter extends DisplayAdapter {
}
@Override
+ public void onScanFinished() {
+ synchronized (getSyncRoot()) {
+ if (mScanState != WifiDisplayStatus.SCAN_STATE_NOT_SCANNING) {
+ mScanState = WifiDisplayStatus.SCAN_STATE_NOT_SCANNING;
+ scheduleStatusChangedBroadcastLocked();
+ }
+ }
+ }
+
+ @Override
public void onDisplayConnecting(WifiDisplay display) {
synchronized (getSyncRoot()) {
display = mPersistentDataStore.applyWifiDisplayAlias(display);
diff --git a/services/java/com/android/server/display/WifiDisplayController.java b/services/java/com/android/server/display/WifiDisplayController.java
index b2939fe7e4d4..dbb59b269bf5 100644
--- a/services/java/com/android/server/display/WifiDisplayController.java
+++ b/services/java/com/android/server/display/WifiDisplayController.java
@@ -27,7 +27,6 @@ import android.database.ContentObserver;
import android.hardware.display.WifiDisplay;
import android.hardware.display.WifiDisplaySessionInfo;
import android.hardware.display.WifiDisplayStatus;
-import android.media.AudioManager;
import android.media.RemoteDisplay;
import android.net.NetworkInfo;
import android.net.Uri;
@@ -75,12 +74,19 @@ 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 = 60;
+ private static final int CONNECTION_TIMEOUT_SECONDS = 30;
private static final int RTSP_TIMEOUT_SECONDS = 30;
private static final int RTSP_TIMEOUT_SECONDS_CERT_MODE = 120;
- private static final int DISCOVER_PEERS_MAX_RETRIES = 10;
- private static final int DISCOVER_PEERS_RETRY_DELAY_MILLIS = 500;
+ // We repeatedly issue calls to discover peers every so often for a few reasons.
+ // 1. The initial request may fail and need to retried.
+ // 2. Discovery will self-abort after any group is initiated, which may not necessarily
+ // be what we want to have happen.
+ // 3. Discovery will self-timeout after 2 minutes, whereas we want discovery to
+ // be occur for as long as a client is requesting it be.
+ // 4. We don't seem to get updated results for displays we've already found until
+ // we ask to discover again, particularly for the isSessionAvailable() property.
+ private static final int DISCOVER_PEERS_INTERVAL_MILLIS = 10000;
private static final int CONNECT_MAX_RETRIES = 3;
private static final int CONNECT_RETRY_DELAY_MILLIS = 500;
@@ -103,12 +109,12 @@ final class WifiDisplayController implements DumpUtils.Dump {
// True if Wifi display is enabled by the user.
private boolean mWifiDisplayOnSetting;
+ // True if a scan was requested independent of whether one is actually in progress.
+ private boolean mScanRequested;
+
// True if there is a call to discoverPeers in progress.
private boolean mDiscoverPeersInProgress;
- // Number of discover peers retries remaining.
- private int mDiscoverPeersRetriesLeft;
-
// The device to which we want to connect, or null if we want to be disconnected.
private WifiP2pDevice mDesiredDevice;
@@ -209,8 +215,8 @@ final class WifiDisplayController implements DumpUtils.Dump {
pw.println("mWfdEnabled=" + mWfdEnabled);
pw.println("mWfdEnabling=" + mWfdEnabling);
pw.println("mNetworkInfo=" + mNetworkInfo);
+ pw.println("mScanRequested=" + mScanRequested);
pw.println("mDiscoverPeersInProgress=" + mDiscoverPeersInProgress);
- pw.println("mDiscoverPeersRetriesLeft=" + mDiscoverPeersRetriesLeft);
pw.println("mDesiredDevice=" + describeWifiP2pDevice(mDesiredDevice));
pw.println("mConnectingDisplay=" + describeWifiP2pDevice(mConnectingDevice));
pw.println("mDisconnectingDisplay=" + describeWifiP2pDevice(mDisconnectingDevice));
@@ -232,8 +238,18 @@ final class WifiDisplayController implements DumpUtils.Dump {
}
}
- public void requestScan() {
- discoverPeers();
+ public void requestStartScan() {
+ if (!mScanRequested) {
+ mScanRequested = true;
+ updateScanState();
+ }
+ }
+
+ public void requestStopScan() {
+ if (mScanRequested) {
+ mScanRequested = false;
+ updateScanState();
+ }
}
public void requestConnect(String address) {
@@ -282,6 +298,7 @@ final class WifiDisplayController implements DumpUtils.Dump {
mWfdEnabling = false;
mWfdEnabled = true;
reportFeatureState();
+ updateScanState();
}
}
@@ -318,6 +335,7 @@ final class WifiDisplayController implements DumpUtils.Dump {
mWfdEnabling = false;
mWfdEnabled = false;
reportFeatureState();
+ updateScanState();
disconnect();
}
}
@@ -340,12 +358,29 @@ final class WifiDisplayController implements DumpUtils.Dump {
WifiDisplayStatus.FEATURE_STATE_OFF;
}
- private void discoverPeers() {
- if (!mDiscoverPeersInProgress) {
- mDiscoverPeersInProgress = true;
- mDiscoverPeersRetriesLeft = DISCOVER_PEERS_MAX_RETRIES;
- handleScanStarted();
- tryDiscoverPeers();
+ private void updateScanState() {
+ if (mScanRequested && mWfdEnabled && mDesiredDevice == null) {
+ if (!mDiscoverPeersInProgress) {
+ Slog.i(TAG, "Starting Wifi display scan.");
+ mDiscoverPeersInProgress = true;
+ handleScanStarted();
+ tryDiscoverPeers();
+ }
+ } else {
+ if (mDiscoverPeersInProgress) {
+ // Cancel automatic retry right away.
+ mHandler.removeCallbacks(mDiscoverPeers);
+
+ // Defer actually stopping discovery if we have a connection attempt in progress.
+ // The wifi display connection attempt often fails if we are not in discovery
+ // mode. So we allow discovery to continue until we give up trying to connect.
+ if (mDesiredDevice == null || mDesiredDevice == mConnectedDevice) {
+ Slog.i(TAG, "Stopping Wifi display scan.");
+ mDiscoverPeersInProgress = false;
+ stopPeerDiscovery();
+ handleScanFinished();
+ }
+ }
}
}
@@ -357,8 +392,9 @@ final class WifiDisplayController implements DumpUtils.Dump {
Slog.d(TAG, "Discover peers succeeded. Requesting peers now.");
}
- mDiscoverPeersInProgress = false;
- requestPeers();
+ if (mDiscoverPeersInProgress) {
+ requestPeers();
+ }
}
@Override
@@ -367,30 +403,28 @@ final class WifiDisplayController implements DumpUtils.Dump {
Slog.d(TAG, "Discover peers failed with reason " + reason + ".");
}
- if (mDiscoverPeersInProgress) {
- if (reason == 0 && mDiscoverPeersRetriesLeft > 0 && mWfdEnabled) {
- mHandler.postDelayed(new Runnable() {
- @Override
- public void run() {
- if (mDiscoverPeersInProgress) {
- if (mDiscoverPeersRetriesLeft > 0 && mWfdEnabled) {
- mDiscoverPeersRetriesLeft -= 1;
- if (DEBUG) {
- Slog.d(TAG, "Retrying discovery. Retries left: "
- + mDiscoverPeersRetriesLeft);
- }
- tryDiscoverPeers();
- } else {
- handleScanFinished();
- mDiscoverPeersInProgress = false;
- }
- }
- }
- }, DISCOVER_PEERS_RETRY_DELAY_MILLIS);
- } else {
- handleScanFinished();
- mDiscoverPeersInProgress = false;
- }
+ // Ignore the error.
+ // We will retry automatically in a little bit.
+ }
+ });
+
+ // Retry discover peers periodically until stopped.
+ mHandler.postDelayed(mDiscoverPeers, DISCOVER_PEERS_INTERVAL_MILLIS);
+ }
+
+ private void stopPeerDiscovery() {
+ mWifiP2pManager.stopPeerDiscovery(mWifiP2pChannel, new ActionListener() {
+ @Override
+ public void onSuccess() {
+ if (DEBUG) {
+ Slog.d(TAG, "Stop peer discovery succeeded.");
+ }
+ }
+
+ @Override
+ public void onFailure(int reason) {
+ if (DEBUG) {
+ Slog.d(TAG, "Stop peer discovery failed with reason " + reason + ".");
}
}
});
@@ -415,7 +449,9 @@ final class WifiDisplayController implements DumpUtils.Dump {
}
}
- handleScanFinished();
+ if (mDiscoverPeersInProgress) {
+ handleScanResults();
+ }
}
});
}
@@ -429,7 +465,7 @@ final class WifiDisplayController implements DumpUtils.Dump {
});
}
- private void handleScanFinished() {
+ private void handleScanResults() {
final int count = mAvailableWifiDisplayPeers.size();
final WifiDisplay[] displays = WifiDisplay.CREATOR.newArray(count);
for (int i = 0; i < count; i++) {
@@ -441,7 +477,16 @@ final class WifiDisplayController implements DumpUtils.Dump {
mHandler.post(new Runnable() {
@Override
public void run() {
- mListener.onScanFinished(displays);
+ mListener.onScanResults(displays);
+ }
+ });
+ }
+
+ private void handleScanFinished() {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mListener.onScanFinished();
}
});
}
@@ -484,6 +529,12 @@ final class WifiDisplayController implements DumpUtils.Dump {
return;
}
+ if (!mWfdEnabled) {
+ Slog.i(TAG, "Ignoring request to connect to Wifi display because the "
+ +" feature is currently disabled: " + device.deviceName);
+ return;
+ }
+
mDesiredDevice = device;
mConnectionRetriesLeft = CONNECT_MAX_RETRIES;
updateConnection();
@@ -508,6 +559,10 @@ final class WifiDisplayController implements DumpUtils.Dump {
* 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 && mConnectedDevice != mDesiredDevice) {
@@ -661,7 +716,7 @@ final class WifiDisplayController implements DumpUtils.Dump {
return; // wait for asynchronous callback
}
- // Step 6. Listen for incoming connections.
+ // Step 6. Listen for incoming RTSP connection.
if (mConnectedDevice != null && mRemoteDisplay == null) {
Inet4Address addr = getInterfaceAddress(mConnectedDeviceGroupInfo);
if (addr == null) {
@@ -817,7 +872,11 @@ final class WifiDisplayController implements DumpUtils.Dump {
}
} else {
mConnectedDeviceGroupInfo = null;
- disconnect();
+
+ // Disconnect if we lost the network while connecting or connected to a display.
+ if (mConnectingDevice != null || mConnectedDevice != null) {
+ disconnect();
+ }
// After disconnection for a group, for some reason we have a tendency
// to get a peer change notification with an empty list of peers.
@@ -828,6 +887,13 @@ final class WifiDisplayController implements DumpUtils.Dump {
}
}
+ private final Runnable mDiscoverPeers = new Runnable() {
+ @Override
+ public void run() {
+ tryDiscoverPeers();
+ }
+ };
+
private final Runnable mConnectionTimeout = new Runnable() {
@Override
public void run() {
@@ -1033,7 +1099,8 @@ final class WifiDisplayController implements DumpUtils.Dump {
void onFeatureStateChanged(int featureState);
void onScanStarted();
- void onScanFinished(WifiDisplay[] availableDisplays);
+ void onScanResults(WifiDisplay[] availableDisplays);
+ void onScanFinished();
void onDisplayConnecting(WifiDisplay display);
void onDisplayConnectionFailed();