summaryrefslogtreecommitdiffstats
path: root/services/java/com/android/server/display
diff options
context:
space:
mode:
Diffstat (limited to 'services/java/com/android/server/display')
-rw-r--r--services/java/com/android/server/display/DisplayManagerService.java129
-rw-r--r--services/java/com/android/server/display/WifiDisplayAdapter.java120
-rw-r--r--services/java/com/android/server/display/WifiDisplayController.java165
3 files changed, 286 insertions, 128 deletions
diff --git a/services/java/com/android/server/display/DisplayManagerService.java b/services/java/com/android/server/display/DisplayManagerService.java
index 249c8b0..bcb677f 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,38 +462,94 @@ 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 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) {
throw new IllegalArgumentException("address must not be null");
}
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
+ "Permission required to connect to a wifi display");
- final boolean trusted = canCallerConfigureWifiDisplay();
final long token = Binder.clearCallingIdentity();
try {
synchronized (mSyncRoot) {
if (mWifiDisplayAdapter != null) {
- mWifiDisplayAdapter.requestConnectLocked(address, trusted);
+ mWifiDisplayAdapter.requestConnectLocked(address);
}
}
} finally {
@@ -499,12 +559,8 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
@Override
public void pauseWifiDisplay() {
- if (mContext.checkCallingPermission(
- android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY"
- + "permission to pause a wifi display session.");
- }
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
+ "Permission required to pause a wifi display session");
final long token = Binder.clearCallingIdentity();
try {
@@ -520,12 +576,8 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
@Override
public void resumeWifiDisplay() {
- if (mContext.checkCallingPermission(
- android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY"
- + "permission to resume a wifi display session.");
- }
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
+ "Permission required to resume a wifi display session");
final long token = Binder.clearCallingIdentity();
try {
@@ -541,6 +593,11 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
@Override // Binder call
public void disconnectWifiDisplay() {
+ // This request does not require special permissions.
+ // Any app can request disconnection from the currently active wifi display.
+ // This exception should no longer be needed once wifi display control moves
+ // to the media router service.
+
final long token = Binder.clearCallingIdentity();
try {
synchronized (mSyncRoot) {
@@ -558,10 +615,8 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
if (address == null) {
throw new IllegalArgumentException("address must not be null");
}
- if (!canCallerConfigureWifiDisplay()) {
- throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY permission to "
- + "rename a wifi display.");
- }
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
+ "Permission required to rename to a wifi display");
final long token = Binder.clearCallingIdentity();
try {
@@ -580,10 +635,8 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
if (address == null) {
throw new IllegalArgumentException("address must not be null");
}
- if (!canCallerConfigureWifiDisplay()) {
- throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY permission to "
- + "forget a wifi display.");
- }
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
+ "Permission required to forget to a wifi display");
final long token = Binder.clearCallingIdentity();
try {
@@ -599,6 +652,9 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
@Override // Binder call
public WifiDisplayStatus getWifiDisplayStatus() {
+ // This request does not require special permissions.
+ // Any app can get information about available wifi displays.
+
final long token = Binder.clearCallingIdentity();
try {
synchronized (mSyncRoot) {
@@ -612,11 +668,6 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
}
}
- private boolean canCallerConfigureWifiDisplay() {
- return mContext.checkCallingPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
- == PackageManager.PERMISSION_GRANTED;
- }
-
@Override // Binder call
public int createVirtualDisplay(IBinder appToken, String packageName,
String name, int width, int height, int densityDpi, Surface surface, int flags) {
@@ -1112,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();
@@ -1139,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);
+ }
}
}
@@ -1239,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;
@@ -1252,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 f7bbdf8..cd57941 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,34 +157,39 @@ 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, final boolean trusted) {
+ public void requestStopScanLocked() {
if (DEBUG) {
- Slog.d(TAG, "requestConnectLocked: address=" + address + ", trusted=" + trusted);
+ Slog.d(TAG, "requestStopScanLocked");
}
- if (!trusted) {
- synchronized (getSyncRoot()) {
- if (!isRememberedDisplayLocked(address)) {
- Slog.w(TAG, "Ignoring request by an untrusted client to connect to "
- + "an unknown wifi display: " + address);
- return;
+ getHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ if (mDisplayController != null) {
+ mDisplayController.requestStopScan();
}
}
+ });
+ }
+
+ public void requestConnectLocked(final String address) {
+ if (DEBUG) {
+ Slog.d(TAG, "requestConnectLocked: address=" + address);
}
getHandler().post(new Runnable() {
@@ -197,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() {
if (DEBUG) {
Slog.d(TAG, "requestPauseLocked");
@@ -400,8 +396,6 @@ final class WifiDisplayAdapter extends DisplayAdapter {
mDisplayDevice = new WifiDisplayDevice(displayToken, name, width, height,
refreshRate, deviceFlags, address, surface);
sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_ADDED);
-
- scheduleUpdateNotificationLocked();
}
private void removeDisplayDeviceLocked() {
@@ -409,8 +403,6 @@ final class WifiDisplayAdapter extends DisplayAdapter {
mDisplayDevice.destroyLocked();
sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_REMOVED);
mDisplayDevice = null;
-
- scheduleUpdateNotificationLocked();
}
}
@@ -457,21 +449,24 @@ final class WifiDisplayAdapter extends DisplayAdapter {
// Runs on the handler.
private void handleUpdateNotification() {
- final boolean isConnected;
+ final int state;
+ final WifiDisplay display;
synchronized (getSyncRoot()) {
if (!mPendingNotificationUpdate) {
return;
}
mPendingNotificationUpdate = false;
- isConnected = (mDisplayDevice != null);
+ state = mActiveDisplayState;
+ display = mActiveDisplay;
}
// Cancel the old notification if there is one.
mNotificationManager.cancelAsUser(null,
- R.string.wifi_display_notification_title, UserHandle.ALL);
+ R.string.wifi_display_notification_disconnect, UserHandle.ALL);
- if (isConnected) {
+ if (state == WifiDisplayStatus.DISPLAY_STATE_CONNECTING
+ || state == WifiDisplayStatus.DISPLAY_STATE_CONNECTED) {
Context context = getContext();
// Initialize pending intents for the notification outside of the lock because
@@ -493,20 +488,38 @@ final class WifiDisplayAdapter extends DisplayAdapter {
// Post the notification.
Resources r = context.getResources();
- Notification notification = new Notification.Builder(context)
- .setContentTitle(r.getString(
- R.string.wifi_display_notification_title))
- .setContentText(r.getString(
- R.string.wifi_display_notification_message))
- .setContentIntent(mSettingsPendingIntent)
- .setSmallIcon(R.drawable.ic_notify_wifidisplay)
- .setOngoing(true)
- .addAction(android.R.drawable.ic_menu_close_clear_cancel,
- r.getString(R.string.wifi_display_notification_disconnect),
- mDisconnectPendingIntent)
- .build();
+ Notification notification;
+ if (state == WifiDisplayStatus.DISPLAY_STATE_CONNECTING) {
+ notification = new Notification.Builder(context)
+ .setContentTitle(r.getString(
+ R.string.wifi_display_notification_connecting_title))
+ .setContentText(r.getString(
+ R.string.wifi_display_notification_connecting_message,
+ display.getFriendlyDisplayName()))
+ .setContentIntent(mSettingsPendingIntent)
+ .setSmallIcon(R.drawable.ic_notification_cast_connecting)
+ .setOngoing(true)
+ .addAction(android.R.drawable.ic_menu_close_clear_cancel,
+ r.getString(R.string.wifi_display_notification_disconnect),
+ mDisconnectPendingIntent)
+ .build();
+ } else {
+ notification = new Notification.Builder(context)
+ .setContentTitle(r.getString(
+ R.string.wifi_display_notification_connected_title))
+ .setContentText(r.getString(
+ R.string.wifi_display_notification_connected_message,
+ display.getFriendlyDisplayName()))
+ .setContentIntent(mSettingsPendingIntent)
+ .setSmallIcon(R.drawable.ic_notification_cast_on)
+ .setOngoing(true)
+ .addAction(android.R.drawable.ic_menu_close_clear_cancel,
+ r.getString(R.string.wifi_display_notification_disconnect),
+ mDisconnectPendingIntent)
+ .build();
+ }
mNotificationManager.notifyAsUser(null,
- R.string.wifi_display_notification_title,
+ R.string.wifi_display_notification_disconnect,
notification, UserHandle.ALL);
}
}
@@ -545,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();
@@ -568,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);
@@ -578,6 +601,7 @@ final class WifiDisplayAdapter extends DisplayAdapter {
mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_CONNECTING;
mActiveDisplay = display;
scheduleStatusChangedBroadcastLocked();
+ scheduleUpdateNotificationLocked();
}
}
}
@@ -590,6 +614,7 @@ final class WifiDisplayAdapter extends DisplayAdapter {
mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED;
mActiveDisplay = null;
scheduleStatusChangedBroadcastLocked();
+ scheduleUpdateNotificationLocked();
}
}
}
@@ -607,6 +632,7 @@ final class WifiDisplayAdapter extends DisplayAdapter {
mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_CONNECTED;
mActiveDisplay = display;
scheduleStatusChangedBroadcastLocked();
+ scheduleUpdateNotificationLocked();
}
}
}
@@ -629,6 +655,7 @@ final class WifiDisplayAdapter extends DisplayAdapter {
mActiveDisplay = display;
renameDisplayDeviceLocked(display.getFriendlyDisplayName());
scheduleStatusChangedBroadcastLocked();
+ scheduleUpdateNotificationLocked();
}
}
}
@@ -644,6 +671,7 @@ final class WifiDisplayAdapter extends DisplayAdapter {
mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED;
mActiveDisplay = null;
scheduleStatusChangedBroadcastLocked();
+ scheduleUpdateNotificationLocked();
}
}
}
diff --git a/services/java/com/android/server/display/WifiDisplayController.java b/services/java/com/android/server/display/WifiDisplayController.java
index 9a4cfb7..dbb59b2 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 RTSP_TIMEOUT_SECONDS = 15;
+ 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();