am ce468a35: Stop wifi display discovery when no longer needed.

* commit 'ce468a35b388ca46578934706b38dbae94941643':
  Stop wifi display discovery when no longer needed.
This commit is contained in:
Jeff Brown
2013-11-21 19:43:00 -08:00
committed by Android Git Automerger
8 changed files with 319 additions and 126 deletions

View File

@ -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. * The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast.
* <p> * <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}. * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}.
* </p> * </p>
* *
* @hide * @hide
*/ */
public void scanWifiDisplays() { public void stopWifiDisplayScan() {
mGlobal.scanWifiDisplays(); mGlobal.stopWifiDisplayScan();
} }
/** /**

View File

@ -72,6 +72,8 @@ public final class DisplayManagerGlobal {
private final SparseArray<DisplayInfo> mDisplayInfoCache = new SparseArray<DisplayInfo>(); private final SparseArray<DisplayInfo> mDisplayInfoCache = new SparseArray<DisplayInfo>();
private int[] mDisplayIdCache; private int[] mDisplayIdCache;
private int mWifiDisplayScanNestCount;
private DisplayManagerGlobal(IDisplayManager dm) { private DisplayManagerGlobal(IDisplayManager dm) {
mDm = dm; mDm = dm;
} }
@ -267,13 +269,34 @@ public final class DisplayManagerGlobal {
} }
} }
public void scanWifiDisplays() { public void startWifiDisplayScan() {
synchronized (mLock) {
if (mWifiDisplayScanNestCount++ == 0) {
registerCallbackIfNeededLocked();
try { try {
mDm.scanWifiDisplays(); mDm.startWifiDisplayScan();
} catch (RemoteException ex) { } catch (RemoteException ex) {
Log.e(TAG, "Failed to scan for Wifi displays.", 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;
}
}
}
public void connectWifiDisplay(String deviceAddress) { public void connectWifiDisplay(String deviceAddress) {
if (deviceAddress == null) { if (deviceAddress == null) {

View File

@ -29,11 +29,14 @@ interface IDisplayManager {
void registerCallback(in IDisplayManagerCallback callback); void registerCallback(in IDisplayManagerCallback callback);
// No permissions required. // Requires CONFIGURE_WIFI_DISPLAY permission.
void scanWifiDisplays(); // The process must have previously registered a callback.
void startWifiDisplayScan();
// Requires CONFIGURE_WIFI_DISPLAY permission to connect to an unknown device. // Requires CONFIGURE_WIFI_DISPLAY permission.
// No permissions required to connect to a known device. void stopWifiDisplayScan();
// Requires CONFIGURE_WIFI_DISPLAY permission.
void connectWifiDisplay(String address); void connectWifiDisplay(String address);
// No permissions required. // No permissions required.
@ -45,6 +48,12 @@ interface IDisplayManager {
// Requires CONFIGURE_WIFI_DISPLAY permission. // Requires CONFIGURE_WIFI_DISPLAY permission.
void forgetWifiDisplay(String address); void forgetWifiDisplay(String address);
// Requires CONFIGURE_WIFI_DISPLAY permission.
void pauseWifiDisplay();
// Requires CONFIGURE_WIFI_DISPLAY permission.
void resumeWifiDisplay();
// No permissions required. // No permissions required.
WifiDisplayStatus getWifiDisplayStatus(); WifiDisplayStatus getWifiDisplayStatus();
@ -55,10 +64,4 @@ interface IDisplayManager {
// No permissions required but must be same Uid as the creator. // No permissions required but must be same Uid as the creator.
void releaseVirtualDisplay(in IBinder token); void releaseVirtualDisplay(in IBinder token);
// Requires CONFIGURE_WIFI_DISPLAY permission.
void pauseWifiDisplay();
// Requires CONFIGURE_WIFI_DISPLAY permission.
void resumeWifiDisplay();
} }

View File

@ -61,9 +61,6 @@ public class MediaRouter {
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
static class Static implements DisplayManager.DisplayListener { 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 Context mAppContext;
final Resources mResources; final Resources mResources;
final IAudioService mAudioService; final IAudioService mAudioService;
@ -87,6 +84,7 @@ public class MediaRouter {
final boolean mCanConfigureWifiDisplays; final boolean mCanConfigureWifiDisplays;
boolean mActivelyScanningWifiDisplays; boolean mActivelyScanningWifiDisplays;
String mPreviousActiveWifiDisplayAddress;
int mDiscoveryRequestRouteTypes; int mDiscoveryRequestRouteTypes;
boolean mDiscoverRequestActiveScan; 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) { Static(Context appContext) {
mAppContext = appContext; mAppContext = appContext;
mResources = Resources.getSystem(); mResources = Resources.getSystem();
@ -279,15 +267,24 @@ public class MediaRouter {
} }
// Update wifi display scanning. // Update wifi display scanning.
if (activeScanWifiDisplay && mCanConfigureWifiDisplays) { // 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;
}
if (activeScanWifiDisplay) {
if (!mActivelyScanningWifiDisplays) { if (!mActivelyScanningWifiDisplays) {
mActivelyScanningWifiDisplays = true; mActivelyScanningWifiDisplays = true;
mHandler.post(mScanWifiDisplays); mDisplayService.startWifiDisplayScan();
} }
} else { } else {
if (mActivelyScanningWifiDisplays) { if (mActivelyScanningWifiDisplays) {
mActivelyScanningWifiDisplays = false; mActivelyScanningWifiDisplays = false;
mHandler.removeCallbacks(mScanWifiDisplays); mDisplayService.stopWifiDisplayScan();
}
} }
} }
@ -945,6 +942,9 @@ public class MediaRouter {
} }
dispatchRouteSelected(types & route.getSupportedTypes(), route); dispatchRouteSelected(types & route.getSupportedTypes(), route);
} }
// The behavior of active scans may depend on the currently selected route.
sStatic.updateDiscoveryRequest();
} }
static void selectDefaultRouteStatic() { static void selectDefaultRouteStatic() {
@ -1291,10 +1291,8 @@ public class MediaRouter {
} }
static void updateWifiDisplayStatus(WifiDisplayStatus status) { static void updateWifiDisplayStatus(WifiDisplayStatus status) {
boolean wantScan = false;
WifiDisplay[] displays; WifiDisplay[] displays;
WifiDisplay activeDisplay; WifiDisplay activeDisplay;
if (status.getFeatureState() == WifiDisplayStatus.FEATURE_STATE_ON) { if (status.getFeatureState() == WifiDisplayStatus.FEATURE_STATE_ON) {
displays = status.getDisplays(); displays = status.getDisplays();
activeDisplay = status.getActiveDisplay(); activeDisplay = status.getActiveDisplay();
@ -1314,6 +1312,8 @@ public class MediaRouter {
displays = WifiDisplay.EMPTY_ARRAY; displays = WifiDisplay.EMPTY_ARRAY;
activeDisplay = null; activeDisplay = null;
} }
String activeDisplayAddress = activeDisplay != null ?
activeDisplay.getDeviceAddress() : null;
// Add or update routes. // Add or update routes.
for (int i = 0; i < displays.length; i++) { for (int i = 0; i < displays.length; i++) {
@ -1323,9 +1323,11 @@ public class MediaRouter {
if (route == null) { if (route == null) {
route = makeWifiDisplayRoute(d, status); route = makeWifiDisplayRoute(d, status);
addRouteStatic(route); addRouteStatic(route);
wantScan = true;
} else { } 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)) { if (d.equals(activeDisplay)) {
selectRouteStatic(route.getSupportedTypes(), route, false); 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) { private static boolean shouldShowWifiDisplay(WifiDisplay d, WifiDisplay activeDisplay) {
@ -1400,7 +1406,8 @@ public class MediaRouter {
} }
private static void updateWifiDisplayRoute( private static void updateWifiDisplayRoute(
RouteInfo route, WifiDisplay display, WifiDisplayStatus wfdStatus) { RouteInfo route, WifiDisplay display, WifiDisplayStatus wfdStatus,
boolean disconnected) {
boolean changed = false; boolean changed = false;
final String newName = display.getFriendlyDisplayName(); final String newName = display.getFriendlyDisplayName();
if (!route.getName().equals(newName)) { if (!route.getName().equals(newName)) {
@ -1418,7 +1425,7 @@ public class MediaRouter {
dispatchRouteChanged(route); dispatchRouteChanged(route);
} }
if (!enabled && route.isSelected()) { if ((!enabled || disconnected) && route.isSelected()) {
// Oops, no longer available. Reselect the default. // Oops, no longer available. Reselect the default.
selectDefaultRouteStatic(); selectDefaultRouteStatic();
} }

View File

@ -692,14 +692,8 @@ class QuickSettingsModel implements BluetoothStateChangeCallback,
} else { } else {
connectedRoute = null; connectedRoute = null;
connecting = false; connecting = false;
final int count = mMediaRouter.getRouteCount(); enabled = mMediaRouter.isRouteAvailable(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY,
for (int i = 0; i < count; i++) { MediaRouter.AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE);
MediaRouter.RouteInfo route = mMediaRouter.getRouteAt(i);
if (route.matchesTypes(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY)) {
enabled = true;
break;
}
}
} }
mRemoteDisplayState.enabled = enabled; mRemoteDisplayState.enabled = enabled;

View File

@ -35,6 +35,7 @@ import android.os.RemoteException;
import android.os.SystemClock; import android.os.SystemClock;
import android.os.SystemProperties; import android.os.SystemProperties;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log;
import android.util.Slog; import android.util.Slog;
import android.util.SparseArray; import android.util.SparseArray;
import android.view.Display; import android.view.Display;
@ -173,6 +174,9 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
// The Wifi display adapter, or null if not registered. // The Wifi display adapter, or null if not registered.
private WifiDisplayAdapter mWifiDisplayAdapter; private WifiDisplayAdapter mWifiDisplayAdapter;
// The number of active wifi display scan requests.
private int mWifiDisplayScanRequestCount;
// The virtual display adapter, or null if not registered. // The virtual display adapter, or null if not registered.
private VirtualDisplayAdapter mVirtualDisplayAdapter; 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) { synchronized (mSyncRoot) {
mCallbacks.remove(pid); mCallbacks.remove(record.mPid);
stopWifiDisplayScanLocked(record);
} }
} }
@Override // Binder call @Override // Binder call
public void scanWifiDisplays() { public void startWifiDisplayScan() {
mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY, 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(); final long token = Binder.clearCallingIdentity();
try { try {
synchronized (mSyncRoot) { synchronized (mSyncRoot) {
if (mWifiDisplayAdapter != null) { CallbackRecord record = mCallbacks.get(callingPid);
mWifiDisplayAdapter.requestScanLocked(); if (record == null) {
throw new IllegalStateException("The calling process has not "
+ "registered an IDisplayManagerCallback.");
} }
startWifiDisplayScanLocked(record);
} }
} finally { } finally {
Binder.restoreCallingIdentity(token); Binder.restoreCallingIdentity(token);
} }
} }
private void startWifiDisplayScanLocked(CallbackRecord record) {
if (!record.mWifiDisplayScanRequested) {
record.mWifiDisplayScanRequested = true;
if (mWifiDisplayScanRequestCount++ == 0) {
if (mWifiDisplayAdapter != null) {
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 @Override // Binder call
public void connectWifiDisplay(String address) { public void connectWifiDisplay(String address) {
if (address == null) { if (address == null) {
@ -1107,6 +1163,7 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
pw.println(" mDefaultViewport=" + mDefaultViewport); pw.println(" mDefaultViewport=" + mDefaultViewport);
pw.println(" mExternalTouchViewport=" + mExternalTouchViewport); pw.println(" mExternalTouchViewport=" + mExternalTouchViewport);
pw.println(" mSingleDisplayDemoMode=" + mSingleDisplayDemoMode); pw.println(" mSingleDisplayDemoMode=" + mSingleDisplayDemoMode);
pw.println(" mWifiDisplayScanRequestCount=" + mWifiDisplayScanRequestCount);
IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
ipw.increaseIndent(); ipw.increaseIndent();
@ -1134,6 +1191,15 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
pw.println(" Display " + displayId + ":"); pw.println(" Display " + displayId + ":");
display.dumpLocked(ipw); 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 class CallbackRecord implements DeathRecipient {
private final int mPid; public final int mPid;
private final IDisplayManagerCallback mCallback; private final IDisplayManagerCallback mCallback;
public boolean mWifiDisplayScanRequested;
public CallbackRecord(int pid, IDisplayManagerCallback callback) { public CallbackRecord(int pid, IDisplayManagerCallback callback) {
mPid = pid; mPid = pid;
mCallback = callback; mCallback = callback;
@ -1247,7 +1315,7 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
if (DEBUG) { if (DEBUG) {
Slog.d(TAG, "Display listener for pid " + mPid + " died."); Slog.d(TAG, "Display listener for pid " + mPid + " died.");
} }
onCallbackDied(mPid); onCallbackDied(this);
} }
public void notifyDisplayEventAsync(int displayId, int event) { public void notifyDisplayEventAsync(int displayId, int event) {

View File

@ -157,16 +157,31 @@ final class WifiDisplayAdapter extends DisplayAdapter {
}); });
} }
public void requestScanLocked() { public void requestStartScanLocked() {
if (DEBUG) { if (DEBUG) {
Slog.d(TAG, "requestScanLocked"); Slog.d(TAG, "requestStartScanLocked");
} }
getHandler().post(new Runnable() { getHandler().post(new Runnable() {
@Override @Override
public void run() { public void run() {
if (mDisplayController != null) { if (mDisplayController != null) {
mDisplayController.requestScan(); mDisplayController.requestStartScan();
}
}
});
}
public void requestStopScanLocked() {
if (DEBUG) {
Slog.d(TAG, "requestStopScanLocked");
}
getHandler().post(new Runnable() {
@Override
public void run() {
if (mDisplayController != null) {
mDisplayController.requestStopScan();
} }
} }
}); });
@ -187,15 +202,6 @@ final class WifiDisplayAdapter extends DisplayAdapter {
}); });
} }
private boolean isRememberedDisplayLocked(String address) {
for (WifiDisplay display : mRememberedDisplays) {
if (display.getDeviceAddress().equals(address)) {
return true;
}
}
return false;
}
public void requestPauseLocked() { public void requestPauseLocked() {
if (DEBUG) { if (DEBUG) {
Slog.d(TAG, "requestPauseLocked"); Slog.d(TAG, "requestPauseLocked");
@ -552,20 +558,20 @@ final class WifiDisplayAdapter extends DisplayAdapter {
} }
@Override @Override
public void onScanFinished(WifiDisplay[] availableDisplays) { public void onScanResults(WifiDisplay[] availableDisplays) {
synchronized (getSyncRoot()) { synchronized (getSyncRoot()) {
availableDisplays = mPersistentDataStore.applyWifiDisplayAliases( availableDisplays = mPersistentDataStore.applyWifiDisplayAliases(
availableDisplays); availableDisplays);
// check if any of the available displays changed canConnect status
boolean changed = !Arrays.equals(mAvailableDisplays, availableDisplays); 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++) { for (int i = 0; !changed && i<availableDisplays.length; i++) {
changed = availableDisplays[i].canConnect() changed = availableDisplays[i].canConnect()
!= mAvailableDisplays[i].canConnect(); != mAvailableDisplays[i].canConnect();
} }
if (mScanState != WifiDisplayStatus.SCAN_STATE_NOT_SCANNING || changed) { if (changed) {
mScanState = WifiDisplayStatus.SCAN_STATE_NOT_SCANNING;
mAvailableDisplays = availableDisplays; mAvailableDisplays = availableDisplays;
fixRememberedDisplayNamesFromAvailableDisplaysLocked(); fixRememberedDisplayNamesFromAvailableDisplaysLocked();
updateDisplaysLocked(); updateDisplaysLocked();
@ -574,6 +580,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 @Override
public void onDisplayConnecting(WifiDisplay display) { public void onDisplayConnecting(WifiDisplay display) {
synchronized (getSyncRoot()) { synchronized (getSyncRoot()) {

View File

@ -27,7 +27,6 @@ import android.database.ContentObserver;
import android.hardware.display.WifiDisplay; import android.hardware.display.WifiDisplay;
import android.hardware.display.WifiDisplaySessionInfo; import android.hardware.display.WifiDisplaySessionInfo;
import android.hardware.display.WifiDisplayStatus; import android.hardware.display.WifiDisplayStatus;
import android.media.AudioManager;
import android.media.RemoteDisplay; import android.media.RemoteDisplay;
import android.net.NetworkInfo; import android.net.NetworkInfo;
import android.net.Uri; 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 DEFAULT_CONTROL_PORT = 7236;
private static final int MAX_THROUGHPUT = 50; 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 = 30;
private static final int RTSP_TIMEOUT_SECONDS_CERT_MODE = 120; private static final int RTSP_TIMEOUT_SECONDS_CERT_MODE = 120;
private static final int DISCOVER_PEERS_MAX_RETRIES = 10; // We repeatedly issue calls to discover peers every so often for a few reasons.
private static final int DISCOVER_PEERS_RETRY_DELAY_MILLIS = 500; // 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_MAX_RETRIES = 3;
private static final int CONNECT_RETRY_DELAY_MILLIS = 500; 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. // True if Wifi display is enabled by the user.
private boolean mWifiDisplayOnSetting; 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. // True if there is a call to discoverPeers in progress.
private boolean mDiscoverPeersInProgress; 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. // The device to which we want to connect, or null if we want to be disconnected.
private WifiP2pDevice mDesiredDevice; private WifiP2pDevice mDesiredDevice;
@ -209,8 +215,8 @@ final class WifiDisplayController implements DumpUtils.Dump {
pw.println("mWfdEnabled=" + mWfdEnabled); pw.println("mWfdEnabled=" + mWfdEnabled);
pw.println("mWfdEnabling=" + mWfdEnabling); pw.println("mWfdEnabling=" + mWfdEnabling);
pw.println("mNetworkInfo=" + mNetworkInfo); pw.println("mNetworkInfo=" + mNetworkInfo);
pw.println("mScanRequested=" + mScanRequested);
pw.println("mDiscoverPeersInProgress=" + mDiscoverPeersInProgress); pw.println("mDiscoverPeersInProgress=" + mDiscoverPeersInProgress);
pw.println("mDiscoverPeersRetriesLeft=" + mDiscoverPeersRetriesLeft);
pw.println("mDesiredDevice=" + describeWifiP2pDevice(mDesiredDevice)); pw.println("mDesiredDevice=" + describeWifiP2pDevice(mDesiredDevice));
pw.println("mConnectingDisplay=" + describeWifiP2pDevice(mConnectingDevice)); pw.println("mConnectingDisplay=" + describeWifiP2pDevice(mConnectingDevice));
pw.println("mDisconnectingDisplay=" + describeWifiP2pDevice(mDisconnectingDevice)); pw.println("mDisconnectingDisplay=" + describeWifiP2pDevice(mDisconnectingDevice));
@ -232,8 +238,18 @@ final class WifiDisplayController implements DumpUtils.Dump {
} }
} }
public void requestScan() { public void requestStartScan() {
discoverPeers(); if (!mScanRequested) {
mScanRequested = true;
updateScanState();
}
}
public void requestStopScan() {
if (mScanRequested) {
mScanRequested = false;
updateScanState();
}
} }
public void requestConnect(String address) { public void requestConnect(String address) {
@ -282,6 +298,7 @@ final class WifiDisplayController implements DumpUtils.Dump {
mWfdEnabling = false; mWfdEnabling = false;
mWfdEnabled = true; mWfdEnabled = true;
reportFeatureState(); reportFeatureState();
updateScanState();
} }
} }
@ -318,6 +335,7 @@ final class WifiDisplayController implements DumpUtils.Dump {
mWfdEnabling = false; mWfdEnabling = false;
mWfdEnabled = false; mWfdEnabled = false;
reportFeatureState(); reportFeatureState();
updateScanState();
disconnect(); disconnect();
} }
} }
@ -340,13 +358,30 @@ final class WifiDisplayController implements DumpUtils.Dump {
WifiDisplayStatus.FEATURE_STATE_OFF; WifiDisplayStatus.FEATURE_STATE_OFF;
} }
private void discoverPeers() { private void updateScanState() {
if (mScanRequested && mWfdEnabled && mDesiredDevice == null) {
if (!mDiscoverPeersInProgress) { if (!mDiscoverPeersInProgress) {
Slog.i(TAG, "Starting Wifi display scan.");
mDiscoverPeersInProgress = true; mDiscoverPeersInProgress = true;
mDiscoverPeersRetriesLeft = DISCOVER_PEERS_MAX_RETRIES;
handleScanStarted(); handleScanStarted();
tryDiscoverPeers(); 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();
}
}
}
} }
private void tryDiscoverPeers() { private void tryDiscoverPeers() {
@ -357,9 +392,10 @@ final class WifiDisplayController implements DumpUtils.Dump {
Slog.d(TAG, "Discover peers succeeded. Requesting peers now."); Slog.d(TAG, "Discover peers succeeded. Requesting peers now.");
} }
mDiscoverPeersInProgress = false; if (mDiscoverPeersInProgress) {
requestPeers(); requestPeers();
} }
}
@Override @Override
public void onFailure(int reason) { public void onFailure(int reason) {
@ -367,30 +403,28 @@ final class WifiDisplayController implements DumpUtils.Dump {
Slog.d(TAG, "Discover peers failed with reason " + reason + "."); Slog.d(TAG, "Discover peers failed with reason " + reason + ".");
} }
if (mDiscoverPeersInProgress) { // Ignore the error.
if (reason == 0 && mDiscoverPeersRetriesLeft > 0 && mWfdEnabled) { // We will retry automatically in a little bit.
mHandler.postDelayed(new Runnable() { }
});
// Retry discover peers periodically until stopped.
mHandler.postDelayed(mDiscoverPeers, DISCOVER_PEERS_INTERVAL_MILLIS);
}
private void stopPeerDiscovery() {
mWifiP2pManager.stopPeerDiscovery(mWifiP2pChannel, new ActionListener() {
@Override @Override
public void run() { public void onSuccess() {
if (mDiscoverPeersInProgress) {
if (mDiscoverPeersRetriesLeft > 0 && mWfdEnabled) {
mDiscoverPeersRetriesLeft -= 1;
if (DEBUG) { if (DEBUG) {
Slog.d(TAG, "Retrying discovery. Retries left: " Slog.d(TAG, "Stop peer discovery succeeded.");
+ mDiscoverPeersRetriesLeft);
}
tryDiscoverPeers();
} else {
handleScanFinished();
mDiscoverPeersInProgress = false;
} }
} }
}
}, DISCOVER_PEERS_RETRY_DELAY_MILLIS); @Override
} else { public void onFailure(int reason) {
handleScanFinished(); if (DEBUG) {
mDiscoverPeersInProgress = false; 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 int count = mAvailableWifiDisplayPeers.size();
final WifiDisplay[] displays = WifiDisplay.CREATOR.newArray(count); final WifiDisplay[] displays = WifiDisplay.CREATOR.newArray(count);
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
@ -441,7 +477,16 @@ final class WifiDisplayController implements DumpUtils.Dump {
mHandler.post(new Runnable() { mHandler.post(new Runnable() {
@Override @Override
public void run() { 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; return;
} }
if (!mWfdEnabled) {
Slog.i(TAG, "Ignoring request to connect to Wifi display because the "
+" feature is currently disabled: " + device.deviceName);
return;
}
mDesiredDevice = device; mDesiredDevice = device;
mConnectionRetriesLeft = CONNECT_MAX_RETRIES; mConnectionRetriesLeft = CONNECT_MAX_RETRIES;
updateConnection(); updateConnection();
@ -508,6 +559,10 @@ final class WifiDisplayController implements DumpUtils.Dump {
* connection is established (or not). * connection is established (or not).
*/ */
private void updateConnection() { 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 // Step 1. Before we try to connect to a new device, tell the system we
// have disconnected from the old one. // have disconnected from the old one.
if (mRemoteDisplay != null && mConnectedDevice != mDesiredDevice) { if (mRemoteDisplay != null && mConnectedDevice != mDesiredDevice) {
@ -661,7 +716,7 @@ final class WifiDisplayController implements DumpUtils.Dump {
return; // wait for asynchronous callback return; // wait for asynchronous callback
} }
// Step 6. Listen for incoming connections. // Step 6. Listen for incoming RTSP connection.
if (mConnectedDevice != null && mRemoteDisplay == null) { if (mConnectedDevice != null && mRemoteDisplay == null) {
Inet4Address addr = getInterfaceAddress(mConnectedDeviceGroupInfo); Inet4Address addr = getInterfaceAddress(mConnectedDeviceGroupInfo);
if (addr == null) { if (addr == null) {
@ -817,7 +872,11 @@ final class WifiDisplayController implements DumpUtils.Dump {
} }
} else { } else {
mConnectedDeviceGroupInfo = null; mConnectedDeviceGroupInfo = null;
// Disconnect if we lost the network while connecting or connected to a display.
if (mConnectingDevice != null || mConnectedDevice != null) {
disconnect(); disconnect();
}
// After disconnection for a group, for some reason we have a tendency // After disconnection for a group, for some reason we have a tendency
// to get a peer change notification with an empty list of peers. // 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() { private final Runnable mConnectionTimeout = new Runnable() {
@Override @Override
public void run() { public void run() {
@ -1033,7 +1099,8 @@ final class WifiDisplayController implements DumpUtils.Dump {
void onFeatureStateChanged(int featureState); void onFeatureStateChanged(int featureState);
void onScanStarted(); void onScanStarted();
void onScanFinished(WifiDisplay[] availableDisplays); void onScanResults(WifiDisplay[] availableDisplays);
void onScanFinished();
void onDisplayConnecting(WifiDisplay display); void onDisplayConnecting(WifiDisplay display);
void onDisplayConnectionFailed(); void onDisplayConnectionFailed();