Merge "Add new wifi display discovery API." into jb-mr1-dev

This commit is contained in:
Jeff Brown
2012-09-08 14:55:02 -07:00
committed by Android (Google) Code Review
13 changed files with 760 additions and 36 deletions

View File

@@ -40,6 +40,28 @@ public final class DisplayManager {
private final Object mLock = new Object();
private final SparseArray<Display> mDisplays = new SparseArray<Display>();
/**
* Broadcast receiver that indicates when the Wifi display status changes.
* <p>
* The status is provided as a {@link WifiDisplayStatus} object in the
* {@link #EXTRA_WIFI_DISPLAY_STATUS} extra.
* </p><p>
* This broadcast is only sent to registered receivers with the
* {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY} permission and can
* only be sent by the system.
* </p>
* @hide
*/
public static final String ACTION_WIFI_DISPLAY_STATUS_CHANGED =
"android.hardware.display.action.WIFI_DISPLAY_STATUS_CHANGED";
/**
* Contains a {@link WifiDisplayStatus} object.
* @hide
*/
public static final String EXTRA_WIFI_DISPLAY_STATUS =
"android.hardware.display.extra.WIFI_DISPLAY_STATUS";
/** @hide */
public DisplayManager(Context context) {
mContext = context;
@@ -126,6 +148,47 @@ public final class DisplayManager {
mGlobal.unregisterDisplayListener(listener);
}
/**
* Initiates a fresh scan of availble Wifi displays.
* The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast.
* @hide
*/
public void scanWifiDisplays() {
mGlobal.scanWifiDisplays();
}
/**
* Connects to a Wifi display.
* The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast.
*
* @param deviceAddress The MAC address of the device to which we should connect.
* @hide
*/
public void connectWifiDisplay(String deviceAddress) {
mGlobal.connectWifiDisplay(deviceAddress);
}
/**
* Disconnects from the current Wifi display.
* The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast.
* @hide
*/
public void disconnectWifiDisplay() {
mGlobal.disconnectWifiDisplay();
}
/**
* Gets the current Wifi display status.
* Watch for changes in the status by registering a broadcast receiver for
* {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED}.
*
* @return The current Wifi display status.
* @hide
*/
public WifiDisplayStatus getWifiDisplayStatus() {
return mGlobal.getWifiDisplayStatus();
}
/**
* Listens for changes in available display devices.
*/

View File

@@ -253,6 +253,43 @@ 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 connectWifiDisplay(String deviceAddress) {
if (deviceAddress == null) {
throw new IllegalArgumentException("deviceAddress must not be null");
}
try {
mDm.connectWifiDisplay(deviceAddress);
} catch (RemoteException ex) {
Log.e(TAG, "Failed to connect to Wifi display " + deviceAddress + ".", ex);
}
}
public void disconnectWifiDisplay() {
try {
mDm.disconnectWifiDisplay();
} catch (RemoteException ex) {
Log.e(TAG, "Failed to disconnect from Wifi display.", ex);
}
}
public WifiDisplayStatus getWifiDisplayStatus() {
try {
return mDm.getWifiDisplayStatus();
} catch (RemoteException ex) {
Log.e(TAG, "Failed to get Wifi display status.", ex);
return new WifiDisplayStatus();
}
}
private final class DisplayManagerCallback extends IDisplayManagerCallback.Stub {
@Override
public void onDisplayEvent(int displayId, int event) {

View File

@@ -17,6 +17,8 @@
package android.hardware.display;
import android.hardware.display.IDisplayManagerCallback;
import android.hardware.display.WifiDisplay;
import android.hardware.display.WifiDisplayStatus;
import android.view.DisplayInfo;
/** @hide */
@@ -25,4 +27,16 @@ interface IDisplayManager {
int[] getDisplayIds();
void registerCallback(in IDisplayManagerCallback callback);
// Requires CONFIGURE_WIFI_DISPLAY permission.
void scanWifiDisplays();
// Requires CONFIGURE_WIFI_DISPLAY permission.
void connectWifiDisplay(String address);
// Requires CONFIGURE_WIFI_DISPLAY permission.
void disconnectWifiDisplay();
// Requires CONFIGURE_WIFI_DISPLAY permission.
WifiDisplayStatus getWifiDisplayStatus();
}

View File

@@ -0,0 +1,19 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.display;
parcelable WifiDisplay;

View File

@@ -0,0 +1,107 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.display;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Describes the properties of a Wifi display.
* <p>
* This object is immutable.
* </p>
*
* @hide
*/
public final class WifiDisplay implements Parcelable {
private final String mDeviceAddress;
private final String mDeviceName;
public static final WifiDisplay[] EMPTY_ARRAY = new WifiDisplay[0];
public static final Creator<WifiDisplay> CREATOR = new Creator<WifiDisplay>() {
public WifiDisplay createFromParcel(Parcel in) {
String deviceAddress = in.readString();
String deviceName = in.readString();
return new WifiDisplay(deviceAddress, deviceName);
}
public WifiDisplay[] newArray(int size) {
return size == 0 ? EMPTY_ARRAY : new WifiDisplay[size];
}
};
public WifiDisplay(String deviceAddress, String deviceName) {
if (deviceAddress == null) {
throw new IllegalArgumentException("deviceAddress must not be null");
}
if (deviceName == null) {
throw new IllegalArgumentException("deviceName must not be null");
}
mDeviceAddress = deviceAddress;
mDeviceName = deviceName;
}
/**
* Gets the MAC address of the Wifi display device.
*/
public String getDeviceAddress() {
return mDeviceAddress;
}
/**
* Gets the name of the Wifi display device.
*/
public String getDeviceName() {
return mDeviceName;
}
@Override
public boolean equals(Object o) {
return o instanceof WifiDisplay && equals((WifiDisplay)o);
}
public boolean equals(WifiDisplay other) {
return other != null
&& mDeviceAddress.equals(other.mDeviceAddress)
&& mDeviceName.equals(other.mDeviceName);
}
@Override
public int hashCode() {
// The address on its own should be sufficiently unique for hashing purposes.
return mDeviceAddress.hashCode();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mDeviceAddress);
dest.writeString(mDeviceName);
}
@Override
public int describeContents() {
return 0;
}
// For debugging purposes only.
@Override
public String toString() {
return mDeviceName + " (" + mDeviceAddress + ")";
}
}

View File

@@ -0,0 +1,19 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.display;
parcelable WifiDisplayStatus;

View File

@@ -0,0 +1,159 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.display;
import android.os.Parcel;
import android.os.Parcelable;
import java.util.Arrays;
/**
* Describes the current global state of Wifi display connectivity, including the
* currently connected display and all known displays.
* <p>
* This object is immutable.
* </p>
*
* @hide
*/
public final class WifiDisplayStatus implements Parcelable {
private final boolean mEnabled;
private final WifiDisplay mConnectedDisplay;
private final WifiDisplay[] mKnownDisplays;
private final boolean mScanInProgress;
private final boolean mConnectionInProgress;
public static final Creator<WifiDisplayStatus> CREATOR = new Creator<WifiDisplayStatus>() {
public WifiDisplayStatus createFromParcel(Parcel in) {
boolean enabled = (in.readInt() != 0);
WifiDisplay connectedDisplay = null;
if (in.readInt() != 0) {
connectedDisplay = WifiDisplay.CREATOR.createFromParcel(in);
}
WifiDisplay[] knownDisplays = WifiDisplay.CREATOR.newArray(in.readInt());
for (int i = 0; i < knownDisplays.length; i++) {
knownDisplays[i] = WifiDisplay.CREATOR.createFromParcel(in);
}
boolean scanInProgress = (in.readInt() != 0);
boolean connectionInProgress = (in.readInt() != 0);
return new WifiDisplayStatus(enabled, connectedDisplay, knownDisplays,
scanInProgress, connectionInProgress);
}
public WifiDisplayStatus[] newArray(int size) {
return new WifiDisplayStatus[size];
}
};
public WifiDisplayStatus() {
this(false, null, WifiDisplay.EMPTY_ARRAY, false, false);
}
public WifiDisplayStatus(boolean enabled,
WifiDisplay connectedDisplay, WifiDisplay[] knownDisplays,
boolean scanInProgress, boolean connectionInProgress) {
if (knownDisplays == null) {
throw new IllegalArgumentException("knownDisplays must not be null");
}
mEnabled = enabled;
mConnectedDisplay = connectedDisplay;
mKnownDisplays = knownDisplays;
mScanInProgress = scanInProgress;
mConnectionInProgress = connectionInProgress;
}
/**
* Returns true if the Wifi display feature is enabled and available for use.
* <p>
* The value of this property reflects whether Wifi and Wifi P2P functions
* are enabled. Enablement is not directly controllable by the user at this
* time, except indirectly such as by turning off Wifi altogether.
* </p>
*/
public boolean isEnabled() {
return mEnabled;
}
/**
* Gets the currently connected Wifi display or null if none.
*/
public WifiDisplay getConnectedDisplay() {
return mConnectedDisplay;
}
/**
* Gets the list of all known Wifi displays, never null.
*/
public WifiDisplay[] getKnownDisplays() {
return mKnownDisplays;
}
/**
* Returns true if there is currently a Wifi display scan in progress.
*/
public boolean isScanInProgress() {
return mScanInProgress;
}
/**
* Returns true if there is currently a Wifi display connection in progress.
*/
public boolean isConnectionInProgress() {
return mConnectionInProgress;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mEnabled ? 1 : 0);
if (mConnectedDisplay != null) {
dest.writeInt(1);
mConnectedDisplay.writeToParcel(dest, flags);
} else {
dest.writeInt(0);
}
dest.writeInt(mKnownDisplays.length);
for (WifiDisplay display : mKnownDisplays) {
display.writeToParcel(dest, flags);
}
dest.writeInt(mScanInProgress ? 1 : 0);
dest.writeInt(mConnectionInProgress ? 1 : 0);
}
@Override
public int describeContents() {
return 0;
}
// For debugging purposes only.
@Override
public String toString() {
return "WifiDisplayStatus{enabled=" + mEnabled
+ ", connectedDisplay=" + mConnectedDisplay
+ ", knownDisplays=" + Arrays.toString(mKnownDisplays)
+ ", scanInProgress=" + mScanInProgress
+ ", connectionInProgress=" + mConnectionInProgress
+ "}";
}
}

View File

@@ -108,6 +108,8 @@
<protected-broadcast
android:name="android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast android:name="android.hardware.display.action.WIFI_DISPLAY_STATUS_CHANGED" />
<protected-broadcast android:name="android.hardware.usb.action.USB_STATE" />
<protected-broadcast android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
<protected-broadcast android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />

View File

@@ -486,7 +486,6 @@
<java-symbol type="string" name="display_manager_hdmi_display_name" />
<java-symbol type="string" name="display_manager_overlay_display_name" />
<java-symbol type="string" name="display_manager_overlay_display_title" />
<java-symbol type="string" name="display_manager_wifi_display_name" />
<java-symbol type="string" name="double_tap_toast" />
<java-symbol type="string" name="elapsed_time_short_format_h_mm_ss" />
<java-symbol type="string" name="elapsed_time_short_format_mm_ss" />

View File

@@ -3688,9 +3688,6 @@
<!-- Title text to show within the overlay. [CHAR LIMIT=50] -->
<string name="display_manager_overlay_display_title"><xliff:g id="name">%1$s</xliff:g>: <xliff:g id="width">%2$d</xliff:g>x<xliff:g id="height">%3$d</xliff:g>, <xliff:g id="dpi">%4$d</xliff:g> dpi</string>
<!-- Name of a wifi display. [CHAR LIMIT=50] -->
<string name="display_manager_wifi_display_name">Wifi display: <xliff:g id="device">%1$s</xliff:g></string>
<!-- Keyguard strings -->
<!-- Label shown on emergency call button in keyguard -->
<string name="kg_emergency_call_label">Emergency call</string>

View File

@@ -24,6 +24,7 @@ import android.content.pm.PackageManager;
import android.hardware.display.DisplayManagerGlobal;
import android.hardware.display.IDisplayManager;
import android.hardware.display.IDisplayManagerCallback;
import android.hardware.display.WifiDisplayStatus;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
@@ -137,6 +138,9 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
// to the surface flinger state.
private boolean mPendingTraversal;
// The Wifi display adapter, or null if not registered.
private WifiDisplayAdapter mWifiDisplayAdapter;
// Temporary callback list, used when sending display events to applications.
// May be used outside of the lock but only on the handler thread.
private final ArrayList<CallbackRecord> mTempCallbacks = new ArrayList<CallbackRecord>();
@@ -315,6 +319,77 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
}
}
@Override // Binder call
public void scanWifiDisplays() {
if (mContext.checkCallingPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY permission");
}
final long token = Binder.clearCallingIdentity();
try {
synchronized (mSyncRoot) {
mWifiDisplayAdapter.requestScanLocked();
}
} finally {
Binder.restoreCallingIdentity(token);
}
}
@Override // Binder call
public void connectWifiDisplay(String address) {
if (mContext.checkCallingPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY permission");
}
if (address == null) {
throw new IllegalArgumentException("address must not be null");
}
final long token = Binder.clearCallingIdentity();
try {
synchronized (mSyncRoot) {
mWifiDisplayAdapter.requestConnectLocked(address);
}
} finally {
Binder.restoreCallingIdentity(token);
}
}
@Override // Binder call
public void disconnectWifiDisplay() {
if (mContext.checkCallingPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY permission");
}
final long token = Binder.clearCallingIdentity();
try {
synchronized (mSyncRoot) {
mWifiDisplayAdapter.requestDisconnectLocked();
}
} finally {
Binder.restoreCallingIdentity(token);
}
}
@Override // Binder call
public WifiDisplayStatus getWifiDisplayStatus() {
if (mContext.checkCallingPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY permission");
}
final long token = Binder.clearCallingIdentity();
try {
synchronized (mSyncRoot) {
return mWifiDisplayAdapter.getWifiDisplayStatusLocked();
}
} finally {
Binder.restoreCallingIdentity(token);
}
}
private void registerDefaultDisplayAdapter() {
// Register default display adapter.
synchronized (mSyncRoot) {
@@ -333,8 +408,9 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
if (shouldRegisterNonEssentialDisplayAdaptersLocked()) {
registerDisplayAdapterLocked(new OverlayDisplayAdapter(
mSyncRoot, mContext, mHandler, mDisplayAdapterListener, mUiHandler));
registerDisplayAdapterLocked(new WifiDisplayAdapter(
mSyncRoot, mContext, mHandler, mDisplayAdapterListener));
mWifiDisplayAdapter = new WifiDisplayAdapter(
mSyncRoot, mContext, mHandler, mDisplayAdapterListener);
registerDisplayAdapterLocked(mWifiDisplayAdapter);
}
}
}

View File

@@ -20,6 +20,10 @@ import com.android.internal.util.DumpUtils;
import com.android.internal.util.IndentingPrintWriter;
import android.content.Context;
import android.content.Intent;
import android.hardware.display.DisplayManager;
import android.hardware.display.WifiDisplay;
import android.hardware.display.WifiDisplayStatus;
import android.media.RemoteDisplay;
import android.os.Handler;
import android.os.IBinder;
@@ -27,6 +31,7 @@ import android.util.Slog;
import android.view.Surface;
import java.io.PrintWriter;
import java.util.Arrays;
/**
* Connects to Wifi displays that implement the Miracast protocol.
@@ -48,6 +53,15 @@ final class WifiDisplayAdapter extends DisplayAdapter {
private WifiDisplayHandle mDisplayHandle;
private WifiDisplayController mDisplayController;
private WifiDisplayStatus mCurrentStatus;
private boolean mEnabled;
private WifiDisplay mConnectedDisplay;
private WifiDisplay[] mKnownDisplays = WifiDisplay.EMPTY_ARRAY;
private boolean mScanInProgress;
private boolean mConnectionInProgress;
private boolean mPendingStatusChangeBroadcast;
public WifiDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
Context context, Handler handler, Listener listener) {
super(syncRoot, context, handler, listener, TAG);
@@ -64,6 +78,14 @@ final class WifiDisplayAdapter extends DisplayAdapter {
mDisplayHandle.dumpLocked(pw);
}
pw.println("mCurrentStatus=" + getWifiDisplayStatusLocked());
pw.println("mEnabled=" + mEnabled);
pw.println("mConnectedDisplay=" + mConnectedDisplay);
pw.println("mKnownDisplays=" + Arrays.toString(mKnownDisplays));
pw.println("mScanInProgress=" + mScanInProgress);
pw.println("mConnectionInProgress=" + mConnectionInProgress);
pw.println("mPendingStatusChangeBroadcast=" + mPendingStatusChangeBroadcast);
// Try to dump the controller state.
if (mDisplayController == null) {
pw.println("mDisplayController=null");
@@ -88,28 +110,160 @@ final class WifiDisplayAdapter extends DisplayAdapter {
});
}
private void connectLocked(String deviceName, String iface) {
disconnectLocked();
String name = getContext().getResources().getString(
com.android.internal.R.string.display_manager_wifi_display_name,
deviceName);
mDisplayHandle = new WifiDisplayHandle(name, iface);
public void requestScanLocked() {
getHandler().post(new Runnable() {
@Override
public void run() {
if (mDisplayController != null) {
mDisplayController.requestScan();
}
}
});
}
private void disconnectLocked() {
public void requestConnectLocked(final String address) {
getHandler().post(new Runnable() {
@Override
public void run() {
if (mDisplayController != null) {
mDisplayController.requestConnect(address);
}
}
});
}
public void requestDisconnectLocked() {
getHandler().post(new Runnable() {
@Override
public void run() {
if (mDisplayController != null) {
mDisplayController.requestDisconnect();
}
}
});
}
public WifiDisplayStatus getWifiDisplayStatusLocked() {
if (mCurrentStatus == null) {
mCurrentStatus = new WifiDisplayStatus(mEnabled,
mConnectedDisplay, mKnownDisplays,
mScanInProgress, mConnectionInProgress);
}
return mCurrentStatus;
}
private void handleConnectLocked(WifiDisplay display, String iface) {
handleDisconnectLocked();
mDisplayHandle = new WifiDisplayHandle(display.getDeviceName(), iface);
}
private void handleDisconnectLocked() {
if (mDisplayHandle != null) {
mDisplayHandle.disposeLocked();
mDisplayHandle = null;
}
}
private void scheduleStatusChangedBroadcastLocked() {
if (!mPendingStatusChangeBroadcast) {
mPendingStatusChangeBroadcast = true;
getHandler().post(mStatusChangeBroadcast);
}
}
private final Runnable mStatusChangeBroadcast = new Runnable() {
@Override
public void run() {
final Intent intent;
synchronized (getSyncRoot()) {
if (!mPendingStatusChangeBroadcast) {
return;
}
mPendingStatusChangeBroadcast = false;
intent = new Intent(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
intent.putExtra(DisplayManager.EXTRA_WIFI_DISPLAY_STATUS,
getWifiDisplayStatusLocked());
}
// Send protected broadcast about wifi display status to receivers that
// have the required permission.
getContext().sendBroadcast(intent,
android.Manifest.permission.CONFIGURE_WIFI_DISPLAY);
}
};
private final WifiDisplayController.Listener mWifiDisplayListener =
new WifiDisplayController.Listener() {
@Override
public void onDisplayConnected(String deviceName, String iface) {
public void onEnablementChanged(boolean enabled) {
synchronized (getSyncRoot()) {
connectLocked(deviceName, iface);
if (mEnabled != enabled) {
mCurrentStatus = null;
mEnabled = enabled;
scheduleStatusChangedBroadcastLocked();
}
}
}
@Override
public void onScanStarted() {
synchronized (getSyncRoot()) {
if (!mScanInProgress) {
mCurrentStatus = null;
mScanInProgress = true;
scheduleStatusChangedBroadcastLocked();
}
}
}
public void onScanFinished(WifiDisplay[] knownDisplays) {
synchronized (getSyncRoot()) {
if (!Arrays.equals(mKnownDisplays, knownDisplays) || mScanInProgress) {
mCurrentStatus = null;
mKnownDisplays = knownDisplays;
mScanInProgress = false;
scheduleStatusChangedBroadcastLocked();
}
}
}
@Override
public void onDisplayConnecting(WifiDisplay display) {
synchronized (getSyncRoot()) {
if (!mConnectionInProgress) {
mCurrentStatus = null;
mConnectionInProgress = true;
scheduleStatusChangedBroadcastLocked();
}
}
}
@Override
public void onDisplayConnectionFailed() {
synchronized (getSyncRoot()) {
if (mConnectionInProgress) {
mCurrentStatus = null;
mConnectionInProgress = false;
scheduleStatusChangedBroadcastLocked();
}
}
}
@Override
public void onDisplayConnected(WifiDisplay display, String iface) {
synchronized (getSyncRoot()) {
handleConnectLocked(display, iface);
if (mConnectedDisplay == null || !mConnectedDisplay.equals(display)
|| mConnectionInProgress) {
mCurrentStatus = null;
mConnectedDisplay = display;
mConnectionInProgress = false;
scheduleStatusChangedBroadcastLocked();
}
}
}
@@ -117,7 +271,14 @@ final class WifiDisplayAdapter extends DisplayAdapter {
public void onDisplayDisconnected() {
// Stop listening.
synchronized (getSyncRoot()) {
disconnectLocked();
handleDisconnectLocked();
if (mConnectedDisplay != null || mConnectionInProgress) {
mCurrentStatus = null;
mConnectedDisplay = null;
mConnectionInProgress = false;
scheduleStatusChangedBroadcastLocked();
}
}
}
};

View File

@@ -22,6 +22,7 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.display.WifiDisplay;
import android.net.NetworkInfo;
import android.net.wifi.p2p.WifiP2pConfig;
import android.net.wifi.p2p.WifiP2pDevice;
@@ -143,6 +144,22 @@ final class WifiDisplayController implements DumpUtils.Dump {
}
}
public void requestScan() {
discoverPeers();
}
public void requestConnect(String address) {
for (WifiP2pDevice device : mKnownWifiDisplayPeers) {
if (device.deviceAddress.equals(address)) {
connect(device);
}
}
}
public void requestDisconnect() {
disconnect();
}
private void enableWfd() {
if (!mWfdEnabled && !mWfdEnabling) {
mWfdEnabling = true;
@@ -160,8 +177,8 @@ final class WifiDisplayController implements DumpUtils.Dump {
Slog.d(TAG, "Successfully set WFD info.");
}
if (mWfdEnabling) {
mWfdEnabled = true;
mWfdEnabling = false;
setWfdEnabled(true);
discoverPeers();
}
}
@@ -177,10 +194,23 @@ final class WifiDisplayController implements DumpUtils.Dump {
}
}
private void setWfdEnabled(final boolean enabled) {
if (mWfdEnabled != enabled) {
mWfdEnabled = enabled;
mHandler.post(new Runnable() {
@Override
public void run() {
mListener.onEnablementChanged(enabled);
}
});
}
}
private void discoverPeers() {
if (!mDiscoverPeersInProgress) {
mDiscoverPeersInProgress = true;
mDiscoverPeersRetriesLeft = DISCOVER_PEERS_MAX_RETRIES;
handleScanStarted();
tryDiscoverPeers();
}
}
@@ -217,12 +247,14 @@ final class WifiDisplayController implements DumpUtils.Dump {
}
tryDiscoverPeers();
} else {
handleScanFinished();
mDiscoverPeersInProgress = false;
}
}
}
}, DISCOVER_PEERS_RETRY_DELAY_MILLIS);
} else {
handleScanFinished();
mDiscoverPeersInProgress = false;
}
}
@@ -249,16 +281,31 @@ final class WifiDisplayController implements DumpUtils.Dump {
}
}
// TODO: shouldn't auto-connect like this, let UI do it explicitly
if (!mKnownWifiDisplayPeers.isEmpty()) {
final WifiP2pDevice device = mKnownWifiDisplayPeers.get(0);
handleScanFinished();
}
});
}
if (device.status == WifiP2pDevice.AVAILABLE) {
connect(device);
}
}
private void handleScanStarted() {
mHandler.post(new Runnable() {
@Override
public void run() {
mListener.onScanStarted();
}
});
}
// TODO: publish this information to applications
private void handleScanFinished() {
final int count = mKnownWifiDisplayPeers.size();
final WifiDisplay[] displays = WifiDisplay.CREATOR.newArray(count);
for (int i = 0; i < count; i++) {
displays[i] = createWifiDisplay(mKnownWifiDisplayPeers.get(i));
}
mHandler.post(new Runnable() {
@Override
public void run() {
mListener.onScanFinished(displays);
}
});
}
@@ -403,6 +450,14 @@ final class WifiDisplayController implements DumpUtils.Dump {
WifiP2pConfig config = new WifiP2pConfig();
config.deviceAddress = mConnectingDevice.deviceAddress;
final WifiDisplay display = createWifiDisplay(mConnectingDevice);
mHandler.post(new Runnable() {
@Override
public void run() {
mListener.onDisplayConnecting(display);
}
});
final WifiP2pDevice newDevice = mDesiredDevice;
mWifiP2pManager.connect(mWifiP2pChannel, config, new ActionListener() {
@Override
@@ -440,14 +495,14 @@ final class WifiDisplayController implements DumpUtils.Dump {
WifiP2pWfdInfo wfdInfo = mConnectedDevice.wfdInfo;
int port = (wfdInfo != null ? wfdInfo.getControlPort() : DEFAULT_CONTROL_PORT);
final String name = mConnectedDevice.deviceName;
final WifiDisplay display = createWifiDisplay(mConnectedDevice);
final String iface = addr.getHostAddress() + ":" + port;
mPublishedDevice = mConnectedDevice;
mHandler.post(new Runnable() {
@Override
public void run() {
mListener.onDisplayConnected(name, iface);
mListener.onDisplayConnected(display, iface);
}
});
}
@@ -463,7 +518,7 @@ final class WifiDisplayController implements DumpUtils.Dump {
enableWfd();
}
} else {
mWfdEnabled = false;
setWfdEnabled(false);
disconnect();
}
}
@@ -537,6 +592,13 @@ final class WifiDisplayController implements DumpUtils.Dump {
if (mDesiredDevice != null) {
Slog.i(TAG, "Wifi display connection failed!");
mHandler.post(new Runnable() {
@Override
public void run() {
mListener.onDisplayConnectionFailed();
}
});
if (mConnectionRetriesLeft > 0) {
mHandler.postDelayed(new Runnable() {
@Override
@@ -575,12 +637,10 @@ final class WifiDisplayController implements DumpUtils.Dump {
private static boolean isWifiDisplay(WifiP2pDevice device) {
// FIXME: the wfdInfo API doesn't work yet
return false;
//return device.deviceName.equals("DWD-300-22ACC2");
//return device.deviceName.startsWith("DWD-")
// || device.deviceName.startsWith("DIRECT-")
// || device.deviceName.startsWith("CAVM-");
//return device.wfdInfo != null && device.wfdInfo.isWfdEnabled();
return device.deviceName.startsWith("DWD-")
|| device.deviceName.startsWith("DIRECT-")
|| device.deviceName.startsWith("CAVM-");
//device.wfdInfo != null && device.wfdInfo.isWfdEnabled();
}
private static String describeWifiP2pDevice(WifiP2pDevice device) {
@@ -591,6 +651,10 @@ final class WifiDisplayController implements DumpUtils.Dump {
return group != null ? group.toString().replace('\n', ',') : "null";
}
private static WifiDisplay createWifiDisplay(WifiP2pDevice device) {
return new WifiDisplay(device.deviceAddress, device.deviceName);
}
private final BroadcastReceiver mWifiP2pReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -628,7 +692,14 @@ final class WifiDisplayController implements DumpUtils.Dump {
* Called on the handler thread when displays are connected or disconnected.
*/
public interface Listener {
void onDisplayConnected(String deviceName, String iface);
void onEnablementChanged(boolean enabled);
void onScanStarted();
void onScanFinished(WifiDisplay[] knownDisplays);
void onDisplayConnecting(WifiDisplay display);
void onDisplayConnectionFailed();
void onDisplayConnected(WifiDisplay display, String iface);
void onDisplayDisconnected();
}
}