am 5de1faca: Merge "wifi-display: add certification options" into klp-dev

* commit '5de1faca166e2241cf9ad1981007caa947a1fc1b':
  wifi-display: add certification options
This commit is contained in:
Chong Zhang
2013-08-26 15:03:00 -07:00
committed by Android Git Automerger
14 changed files with 535 additions and 17 deletions

View File

@@ -325,6 +325,16 @@ public final class DisplayManager {
mGlobal.connectWifiDisplay(deviceAddress);
}
/** @hide */
public void pauseWifiDisplay() {
mGlobal.pauseWifiDisplay();
}
/** @hide */
public void resumeWifiDisplay() {
mGlobal.resumeWifiDisplay();
}
/**
* Disconnects from the current Wifi display.
* The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast.

View File

@@ -287,6 +287,22 @@ public final class DisplayManagerGlobal {
}
}
public void pauseWifiDisplay() {
try {
mDm.pauseWifiDisplay();
} catch (RemoteException ex) {
Log.e(TAG, "Failed to pause Wifi display.", ex);
}
}
public void resumeWifiDisplay() {
try {
mDm.resumeWifiDisplay();
} catch (RemoteException ex) {
Log.e(TAG, "Failed to resume Wifi display.", ex);
}
}
public void disconnectWifiDisplay() {
try {
mDm.disconnectWifiDisplay();

View File

@@ -55,4 +55,10 @@ 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();
}

View File

@@ -0,0 +1,116 @@
/*
* 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;
/**
* This class contains information regarding a wifi display session
* (such as session id, source ip address, etc.). This is needed for
* Wifi Display Certification process.
* <p>
* This object is immutable.
* </p>
*
* @hide
*/
public final class WifiDisplaySessionInfo implements Parcelable {
private final boolean mClient;
private final int mSessionId;
private final String mGroupId;
private final String mPassphrase;
private final String mIP;
public static final Creator<WifiDisplaySessionInfo> CREATOR =
new Creator<WifiDisplaySessionInfo>() {
@Override
public WifiDisplaySessionInfo createFromParcel(Parcel in) {
boolean client = (in.readInt() != 0);
int session = in.readInt();
String group = in.readString();
String pp = in.readString();
String ip = in.readString();
return new WifiDisplaySessionInfo(client, session, group, pp, ip);
}
@Override
public WifiDisplaySessionInfo[] newArray(int size) {
return new WifiDisplaySessionInfo[size];
}
};
public WifiDisplaySessionInfo() {
this(true, 0, "", "", "");
}
public WifiDisplaySessionInfo(
boolean client, int session, String group, String pp, String ip) {
mClient = client;
mSessionId = session;
mGroupId = group;
mPassphrase = pp;
mIP = ip;
}
public boolean isClient() {
return mClient;
}
public int getSessionId() {
return mSessionId;
}
public String getGroupId() {
return mGroupId;
}
public String getPassphrase() {
return mPassphrase;
}
public String getIP() {
return mIP;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mClient ? 1 : 0);
dest.writeInt(mSessionId);
dest.writeString(mGroupId);
dest.writeString(mPassphrase);
dest.writeString(mIP);
}
@Override
public int describeContents() {
return 0;
}
// For debugging purposes only.
@Override
public String toString() {
return "WifiDisplaySessionInfo:"
+"\n Client/Owner: " + (mClient ? "Client":"Owner")
+"\n GroupId: " + mGroupId
+"\n Passphrase: " + mPassphrase
+"\n SessionId: " + mSessionId
+"\n IP Address: " + mIP
;
}
}

View File

@@ -39,6 +39,9 @@ public final class WifiDisplayStatus implements Parcelable {
private final WifiDisplay mActiveDisplay;
private final WifiDisplay[] mDisplays;
/** Session info needed for Miracast Certification */
private final WifiDisplaySessionInfo mSessionInfo;
/** Feature state: Wifi display is not available on this device. */
public static final int FEATURE_STATE_UNAVAILABLE = 0;
/** Feature state: Wifi display is disabled, probably because Wifi is disabled. */
@@ -76,8 +79,11 @@ public final class WifiDisplayStatus implements Parcelable {
displays[i] = WifiDisplay.CREATOR.createFromParcel(in);
}
WifiDisplaySessionInfo sessionInfo =
WifiDisplaySessionInfo.CREATOR.createFromParcel(in);
return new WifiDisplayStatus(featureState, scanState, activeDisplayState,
activeDisplay, displays);
activeDisplay, displays, sessionInfo);
}
public WifiDisplayStatus[] newArray(int size) {
@@ -87,11 +93,11 @@ public final class WifiDisplayStatus implements Parcelable {
public WifiDisplayStatus() {
this(FEATURE_STATE_UNAVAILABLE, SCAN_STATE_NOT_SCANNING, DISPLAY_STATE_NOT_CONNECTED,
null, WifiDisplay.EMPTY_ARRAY);
null, WifiDisplay.EMPTY_ARRAY, null);
}
public WifiDisplayStatus(int featureState, int scanState,
int activeDisplayState, WifiDisplay activeDisplay, WifiDisplay[] displays) {
public WifiDisplayStatus(int featureState, int scanState, int activeDisplayState,
WifiDisplay activeDisplay, WifiDisplay[] displays, WifiDisplaySessionInfo sessionInfo) {
if (displays == null) {
throw new IllegalArgumentException("displays must not be null");
}
@@ -101,6 +107,8 @@ public final class WifiDisplayStatus implements Parcelable {
mActiveDisplayState = activeDisplayState;
mActiveDisplay = activeDisplay;
mDisplays = displays;
mSessionInfo = (sessionInfo != null) ? sessionInfo : new WifiDisplaySessionInfo();
}
/**
@@ -144,13 +152,20 @@ public final class WifiDisplayStatus implements Parcelable {
/**
* Gets the list of Wifi displays, returns a combined list of all available
* Wifi displays as reported by the most recent scan, and all remembered
* Wifi displays as reported by the most recent scan, and all remembered
* Wifi displays (not necessarily available at the time).
*/
public WifiDisplay[] getDisplays() {
return mDisplays;
}
/**
* Gets the Wifi display session info (required for certification only)
*/
public WifiDisplaySessionInfo getSessionInfo() {
return mSessionInfo;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mFeatureState);
@@ -168,6 +183,8 @@ public final class WifiDisplayStatus implements Parcelable {
for (WifiDisplay display : mDisplays) {
display.writeToParcel(dest, flags);
}
mSessionInfo.writeToParcel(dest, flags);
}
@Override
@@ -183,6 +200,7 @@ public final class WifiDisplayStatus implements Parcelable {
+ ", activeDisplayState=" + mActiveDisplayState
+ ", activeDisplay=" + mActiveDisplay
+ ", displays=" + Arrays.toString(mDisplays)
+ ", sessionInfo=" + mSessionInfo
+ "}";
}
}

View File

@@ -5074,6 +5074,14 @@ public final class Settings {
*/
public static final String WIFI_DISPLAY_ON = "wifi_display_on";
/**
* Whether Wifi display certification mode is enabled/disabled
* 0=disabled. 1=enabled.
* @hide
*/
public static final String WIFI_DISPLAY_CERTIFICATION_ON =
"wifi_display_certification_on";
/**
* Whether to notify the user of open networks.
* <p>

View File

@@ -61,7 +61,7 @@ protected:
public:
virtual void onDisplayConnected(const sp<IGraphicBufferProducer>& bufferProducer,
uint32_t width, uint32_t height, uint32_t flags) {
uint32_t width, uint32_t height, uint32_t flags, uint32_t session) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
jobject surfaceObj = android_view_Surface_createFromIGraphicBufferProducer(env, bufferProducer);
@@ -73,7 +73,7 @@ public:
env->CallVoidMethod(mRemoteDisplayObjGlobal,
gRemoteDisplayClassInfo.notifyDisplayConnected,
surfaceObj, width, height, flags);
surfaceObj, width, height, flags, session);
env->DeleteLocalRef(surfaceObj);
checkAndClearExceptionFromCallback(env, "notifyDisplayConnected");
}
@@ -117,6 +117,14 @@ public:
mDisplay->dispose();
}
void pause() {
mDisplay->pause();
}
void resume() {
mDisplay->resume();
}
private:
sp<IRemoteDisplay> mDisplay;
sp<NativeRemoteDisplayClient> mClient;
@@ -149,6 +157,16 @@ static jint nativeListen(JNIEnv* env, jobject remoteDisplayObj, jstring ifaceStr
return reinterpret_cast<jint>(wrapper);
}
static void nativePause(JNIEnv* env, jobject remoteDisplayObj, jint ptr) {
NativeRemoteDisplay* wrapper = reinterpret_cast<NativeRemoteDisplay*>(ptr);
wrapper->pause();
}
static void nativeResume(JNIEnv* env, jobject remoteDisplayObj, jint ptr) {
NativeRemoteDisplay* wrapper = reinterpret_cast<NativeRemoteDisplay*>(ptr);
wrapper->resume();
}
static void nativeDispose(JNIEnv* env, jobject remoteDisplayObj, jint ptr) {
NativeRemoteDisplay* wrapper = reinterpret_cast<NativeRemoteDisplay*>(ptr);
delete wrapper;
@@ -161,6 +179,10 @@ static JNINativeMethod gMethods[] = {
(void*)nativeListen },
{"nativeDispose", "(I)V",
(void*)nativeDispose },
{"nativePause", "(I)V",
(void*)nativePause },
{"nativeResume", "(I)V",
(void*)nativeResume },
};
int register_android_media_RemoteDisplay(JNIEnv* env)
@@ -171,7 +193,7 @@ int register_android_media_RemoteDisplay(JNIEnv* env)
jclass clazz = env->FindClass("android/media/RemoteDisplay");
gRemoteDisplayClassInfo.notifyDisplayConnected =
env->GetMethodID(clazz, "notifyDisplayConnected",
"(Landroid/view/Surface;III)V");
"(Landroid/view/Surface;IIII)V");
gRemoteDisplayClassInfo.notifyDisplayDisconnected =
env->GetMethodID(clazz, "notifyDisplayDisconnected", "()V");
gRemoteDisplayClassInfo.notifyDisplayError =

View File

@@ -42,6 +42,8 @@ public final class RemoteDisplay {
private native int nativeListen(String iface);
private native void nativeDispose(int ptr);
private native void nativePause(int ptr);
private native void nativeResume(int ptr);
private RemoteDisplay(Listener listener, Handler handler) {
mListener = listener;
@@ -87,6 +89,14 @@ public final class RemoteDisplay {
dispose(false);
}
public void pause() {
nativePause(mPtr);
}
public void resume() {
nativeResume(mPtr);
}
private void dispose(boolean finalized) {
if (mPtr != 0) {
if (mGuard != null) {
@@ -113,11 +123,11 @@ public final class RemoteDisplay {
// Called from native.
private void notifyDisplayConnected(final Surface surface,
final int width, final int height, final int flags) {
final int width, final int height, final int flags, final int session) {
mHandler.post(new Runnable() {
@Override
public void run() {
mListener.onDisplayConnected(surface, width, height, flags);
mListener.onDisplayConnected(surface, width, height, flags, session);
}
});
}
@@ -146,7 +156,8 @@ public final class RemoteDisplay {
* Listener invoked when the remote display connection changes state.
*/
public interface Listener {
void onDisplayConnected(Surface surface, int width, int height, int flags);
void onDisplayConnected(Surface surface,
int width, int height, int flags, int session);
void onDisplayDisconnected();
void onDisplayError(int error);
}

View File

@@ -497,6 +497,48 @@ 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.");
}
final long token = Binder.clearCallingIdentity();
try {
synchronized (mSyncRoot) {
if (mWifiDisplayAdapter != null) {
mWifiDisplayAdapter.requestPauseLocked();
}
}
} finally {
Binder.restoreCallingIdentity(token);
}
}
@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.");
}
final long token = Binder.clearCallingIdentity();
try {
synchronized (mSyncRoot) {
if (mWifiDisplayAdapter != null) {
mWifiDisplayAdapter.requestResumeLocked();
}
}
} finally {
Binder.restoreCallingIdentity(token);
}
}
@Override // Binder call
public void disconnectWifiDisplay() {
final long token = Binder.clearCallingIdentity();

View File

@@ -30,6 +30,7 @@ import android.content.IntentFilter;
import android.content.res.Resources;
import android.hardware.display.DisplayManager;
import android.hardware.display.WifiDisplay;
import android.hardware.display.WifiDisplaySessionInfo;
import android.hardware.display.WifiDisplayStatus;
import android.media.RemoteDisplay;
import android.os.Handler;
@@ -93,6 +94,7 @@ final class WifiDisplayAdapter extends DisplayAdapter {
private WifiDisplay[] mDisplays = WifiDisplay.EMPTY_ARRAY;
private WifiDisplay[] mAvailableDisplays = WifiDisplay.EMPTY_ARRAY;
private WifiDisplay[] mRememberedDisplays = WifiDisplay.EMPTY_ARRAY;
private WifiDisplaySessionInfo mSessionInfo;
private boolean mPendingStatusChangeBroadcast;
private boolean mPendingNotificationUpdate;
@@ -204,6 +206,36 @@ final class WifiDisplayAdapter extends DisplayAdapter {
return false;
}
public void requestPauseLocked() {
if (DEBUG) {
Slog.d(TAG, "requestPauseLocked");
}
getHandler().post(new Runnable() {
@Override
public void run() {
if (mDisplayController != null) {
mDisplayController.requestPause();
}
}
});
}
public void requestResumeLocked() {
if (DEBUG) {
Slog.d(TAG, "requestResumeLocked");
}
getHandler().post(new Runnable() {
@Override
public void run() {
if (mDisplayController != null) {
mDisplayController.requestResume();
}
}
});
}
public void requestDisconnectLocked() {
if (DEBUG) {
Slog.d(TAG, "requestDisconnectedLocked");
@@ -267,7 +299,7 @@ final class WifiDisplayAdapter extends DisplayAdapter {
if (mCurrentStatus == null) {
mCurrentStatus = new WifiDisplayStatus(
mFeatureState, mScanState, mActiveDisplayState,
mActiveDisplay, mDisplays);
mActiveDisplay, mDisplays, mSessionInfo);
}
if (DEBUG) {
@@ -579,6 +611,14 @@ final class WifiDisplayAdapter extends DisplayAdapter {
}
}
@Override
public void onDisplaySessionInfo(WifiDisplaySessionInfo sessionInfo) {
synchronized (getSyncRoot()) {
mSessionInfo = sessionInfo;
scheduleStatusChangedBroadcastLocked();
}
}
@Override
public void onDisplayChanged(WifiDisplay display) {
synchronized (getSyncRoot()) {

View File

@@ -25,6 +25,7 @@ import android.content.Intent;
import android.content.IntentFilter;
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;
@@ -76,6 +77,7 @@ final class WifiDisplayController implements DumpUtils.Dump {
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 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;
@@ -146,6 +148,10 @@ final class WifiDisplayController implements DumpUtils.Dump {
private int mAdvertisedDisplayHeight;
private int mAdvertisedDisplayFlags;
// Certification
private boolean mWifiDisplayCertMode;
private WifiP2pDevice mThisDevice;
public WifiDisplayController(Context context, Handler handler, Listener listener) {
mContext = context;
mHandler = handler;
@@ -158,6 +164,7 @@ final class WifiDisplayController implements DumpUtils.Dump {
intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
context.registerReceiver(mWifiP2pReceiver, intentFilter, null, mHandler);
ContentObserver settingsObserver = new ContentObserver(mHandler) {
@@ -170,6 +177,8 @@ final class WifiDisplayController implements DumpUtils.Dump {
final ContentResolver resolver = mContext.getContentResolver();
resolver.registerContentObserver(Settings.Global.getUriFor(
Settings.Global.WIFI_DISPLAY_ON), false, settingsObserver);
resolver.registerContentObserver(Settings.Global.getUriFor(
Settings.Global.WIFI_DISPLAY_CERTIFICATION_ON), false, settingsObserver);
updateSettings();
}
@@ -177,6 +186,8 @@ final class WifiDisplayController implements DumpUtils.Dump {
final ContentResolver resolver = mContext.getContentResolver();
mWifiDisplayOnSetting = Settings.Global.getInt(resolver,
Settings.Global.WIFI_DISPLAY_ON, 0) != 0;
mWifiDisplayCertMode = Settings.Global.getInt(resolver,
Settings.Global.WIFI_DISPLAY_CERTIFICATION_ON, 0) != 0;
updateWfdEnableState();
}
@@ -223,6 +234,18 @@ final class WifiDisplayController implements DumpUtils.Dump {
}
}
public void requestPause() {
if (mRemoteDisplay != null) {
mRemoteDisplay.pause();
}
}
public void requestResume() {
if (mRemoteDisplay != null) {
mRemoteDisplay.resume();
}
}
public void requestDisconnect() {
disconnect();
}
@@ -482,6 +505,7 @@ final class WifiDisplayController implements DumpUtils.Dump {
Slog.i(TAG, "Disconnecting from Wifi display: " + mConnectedDevice.deviceName);
mDisconnectingDevice = mConnectedDevice;
mConnectedDevice = null;
mConnectedDeviceGroupInfo = null;
unadvertiseDisplay();
@@ -548,8 +572,12 @@ final class WifiDisplayController implements DumpUtils.Dump {
return; // wait for asynchronous callback
}
// Step 4. If we wanted to disconnect, then mission accomplished.
// Step 4. If we wanted to disconnect, or we're updating after starting an
// autonomous GO, then mission accomplished.
if (mDesiredDevice == null) {
if (mWifiDisplayCertMode) {
mListener.onDisplaySessionInfo(getSessionInfo(mConnectedDeviceGroupInfo, 0));
}
unadvertiseDisplay();
return; // done
}
@@ -625,13 +653,18 @@ final class WifiDisplayController implements DumpUtils.Dump {
mRemoteDisplay = RemoteDisplay.listen(iface, new RemoteDisplay.Listener() {
@Override
public void onDisplayConnected(Surface surface,
int width, int height, int flags) {
int width, int height, int flags, int session) {
if (mConnectedDevice == oldDevice && !mRemoteDisplayConnected) {
Slog.i(TAG, "Opened RTSP connection with Wifi display: "
+ mConnectedDevice.deviceName);
mRemoteDisplayConnected = true;
mHandler.removeCallbacks(mRtspTimeout);
if (mWifiDisplayCertMode) {
mListener.onDisplaySessionInfo(
getSessionInfo(mConnectedDeviceGroupInfo, session));
}
final WifiDisplay display = createWifiDisplay(mConnectedDevice);
advertiseDisplay(display, surface, width, height, flags);
}
@@ -658,10 +691,31 @@ final class WifiDisplayController implements DumpUtils.Dump {
}
}, mHandler);
mHandler.postDelayed(mRtspTimeout, RTSP_TIMEOUT_SECONDS * 1000);
// Use extended timeout value for certification, as some tests require user inputs
int rtspTimeout = mWifiDisplayCertMode ?
RTSP_TIMEOUT_SECONDS_CERT_MODE : RTSP_TIMEOUT_SECONDS;
mHandler.postDelayed(mRtspTimeout, rtspTimeout * 1000);
}
}
private WifiDisplaySessionInfo getSessionInfo(WifiP2pGroup info, int session) {
if (info == null) {
return null;
}
Inet4Address addr = getInterfaceAddress(info);
WifiDisplaySessionInfo sessionInfo = new WifiDisplaySessionInfo(
!info.getOwner().deviceAddress.equals(mThisDevice.deviceAddress),
session,
info.getOwner().deviceAddress + " " + info.getNetworkName(),
info.getPassphrase(),
(addr != null) ? addr.getHostAddress() : "");
if (DEBUG) {
Slog.d(TAG, sessionInfo.toString());
}
return sessionInfo;
}
private void handleStateChanged(boolean enabled) {
mWifiP2pEnabled = enabled;
updateWfdEnableState();
@@ -676,7 +730,7 @@ final class WifiDisplayController implements DumpUtils.Dump {
private void handleConnectionChanged(NetworkInfo networkInfo) {
mNetworkInfo = networkInfo;
if (mWfdEnabled && networkInfo.isConnected()) {
if (mDesiredDevice != null) {
if (mDesiredDevice != null || mWifiDisplayCertMode) {
mWifiP2pManager.requestGroupInfo(mWifiP2pChannel, new GroupInfoListener() {
@Override
public void onGroupInfoAvailable(WifiP2pGroup info) {
@@ -698,6 +752,25 @@ final class WifiDisplayController implements DumpUtils.Dump {
return;
}
if (mWifiDisplayCertMode) {
boolean owner = info.getOwner().deviceAddress
.equals(mThisDevice.deviceAddress);
if (owner && info.getClientList().isEmpty()) {
// this is the case when we started Autonomous GO,
// and no client has connected, save group info
// and updateConnection()
mConnectingDevice = mDesiredDevice = null;
mConnectedDeviceGroupInfo = info;
updateConnection();
} else if (mConnectingDevice == null && mDesiredDevice == null) {
// this is the case when we received an incoming connection
// from the sink, update both mConnectingDevice and mDesiredDevice
// then proceed to updateConnection() below
mConnectingDevice = mDesiredDevice = owner ?
info.getClientList().iterator().next() : info.getOwner();
}
}
if (mConnectingDevice != null && mConnectingDevice == mDesiredDevice) {
Slog.i(TAG, "Connected to Wifi display: "
+ mConnectingDevice.deviceName);
@@ -712,6 +785,7 @@ final class WifiDisplayController implements DumpUtils.Dump {
});
}
} else {
mConnectedDeviceGroupInfo = null;
disconnect();
// After disconnection for a group, for some reason we have a tendency
@@ -910,6 +984,13 @@ final class WifiDisplayController implements DumpUtils.Dump {
}
handleConnectionChanged(networkInfo);
} else if (action.equals(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION)) {
mThisDevice = (WifiP2pDevice) intent.getParcelableExtra(
WifiP2pManager.EXTRA_WIFI_P2P_DEVICE);
if (DEBUG) {
Slog.d(TAG, "Received WIFI_P2P_THIS_DEVICE_CHANGED_ACTION: mThisDevice= "
+ mThisDevice);
}
}
}
};
@@ -928,6 +1009,7 @@ final class WifiDisplayController implements DumpUtils.Dump {
void onDisplayChanged(WifiDisplay display);
void onDisplayConnected(WifiDisplay display,
Surface surface, int width, int height, int flags);
void onDisplaySessionInfo(WifiDisplaySessionInfo sessionInfo);
void onDisplayDisconnected();
}
}

View File

@@ -619,6 +619,37 @@ public class WifiNative {
return doBooleanCommand("P2P_LISTEN " + timeout);
}
public boolean p2pExtListen(boolean enable, int period, int interval) {
if (enable && interval < period) {
return false;
}
return doBooleanCommand("P2P_EXT_LISTEN"
+ (enable ? (" " + period + " " + interval) : ""));
}
public boolean p2pSetChannel(int lc, int oc) {
if (DBG) Log.d(mTAG, "p2pSetChannel: lc="+lc+", oc="+oc);
if (lc >=1 && lc <= 11) {
if (!doBooleanCommand("P2P_SET listen_channel " + lc)) {
return false;
}
} else if (lc != 0) {
return false;
}
if (oc >= 1 && oc <= 165 ) {
int freq = (oc <= 14 ? 2407 : 5000) + oc * 5;
return doBooleanCommand("P2P_SET disallow_freq 1000-"
+ (freq - 5) + "," + (freq + 5) + "-6000");
} else if (oc == 0) {
/* oc==0 disables "P2P_SET disallow_freq" (enables all freqs) */
return doBooleanCommand("P2P_SET disallow_freq \"\"");
}
return false;
}
public boolean p2pFlush() {
return doBooleanCommand("P2P_FLUSH");
}

View File

@@ -30,6 +30,7 @@ import android.net.wifi.p2p.nsd.WifiP2pServiceResponse;
import android.net.wifi.p2p.nsd.WifiP2pUpnpServiceInfo;
import android.net.wifi.p2p.nsd.WifiP2pUpnpServiceResponse;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Handler;
import android.os.Looper;
@@ -430,6 +431,28 @@ public class WifiP2pManager {
/** @hide */
public static final int START_WPS_SUCCEEDED = BASE + 64;
/** @hide */
public static final int START_LISTEN = BASE + 65;
/** @hide */
public static final int START_LISTEN_FAILED = BASE + 66;
/** @hide */
public static final int START_LISTEN_SUCCEEDED = BASE + 67;
/** @hide */
public static final int STOP_LISTEN = BASE + 68;
/** @hide */
public static final int STOP_LISTEN_FAILED = BASE + 69;
/** @hide */
public static final int STOP_LISTEN_SUCCEEDED = BASE + 70;
/** @hide */
public static final int SET_CHANNEL = BASE + 71;
/** @hide */
public static final int SET_CHANNEL_FAILED = BASE + 72;
/** @hide */
public static final int SET_CHANNEL_SUCCEEDED = BASE + 73;
/**
* Create a new WifiP2pManager instance. Applications use
* {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
@@ -667,6 +690,9 @@ public class WifiP2pManager {
case DELETE_PERSISTENT_GROUP_FAILED:
case SET_WFD_INFO_FAILED:
case START_WPS_FAILED:
case START_LISTEN_FAILED:
case STOP_LISTEN_FAILED:
case SET_CHANNEL_FAILED:
if (listener != null) {
((ActionListener) listener).onFailure(message.arg1);
}
@@ -689,6 +715,9 @@ public class WifiP2pManager {
case DELETE_PERSISTENT_GROUP_SUCCEEDED:
case SET_WFD_INFO_SUCCEEDED:
case START_WPS_SUCCEEDED:
case START_LISTEN_SUCCEEDED:
case STOP_LISTEN_SUCCEEDED:
case SET_CHANNEL_SUCCEEDED:
if (listener != null) {
((ActionListener) listener).onSuccess();
}
@@ -955,6 +984,22 @@ public class WifiP2pManager {
c.mAsyncChannel.sendMessage(REMOVE_GROUP, 0, c.putListener(listener));
}
/** @hide */
public void listen(Channel c, boolean enable, ActionListener listener) {
checkChannel(c);
c.mAsyncChannel.sendMessage(enable ? START_LISTEN : STOP_LISTEN,
0, c.putListener(listener));
}
/** @hide */
public void setWifiP2pChannels(Channel c, int lc, int oc, ActionListener listener) {
checkChannel(c);
Bundle p2pChannels = new Bundle();
p2pChannels.putInt("lc", lc);
p2pChannels.putInt("oc", oc);
c.mAsyncChannel.sendMessage(SET_CHANNEL, 0, c.putListener(listener), p2pChannels);
}
/**
* Start a Wi-Fi Protected Setup (WPS) session.
*

View File

@@ -48,6 +48,7 @@ import android.net.wifi.p2p.nsd.WifiP2pServiceInfo;
import android.net.wifi.p2p.nsd.WifiP2pServiceRequest;
import android.net.wifi.p2p.nsd.WifiP2pServiceResponse;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.INetworkManagementService;
import android.os.Handler;
@@ -628,6 +629,9 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
case DhcpStateMachine.CMD_ON_QUIT:
case WifiMonitor.P2P_PROV_DISC_FAILURE_EVENT:
case SET_MIRACAST_MODE:
case WifiP2pManager.START_LISTEN:
case WifiP2pManager.STOP_LISTEN:
case WifiP2pManager.SET_CHANNEL:
break;
case WifiStateMachine.CMD_ENABLE_P2P:
// Enable is lazy and has no response
@@ -729,7 +733,16 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
replyToMessage(message, WifiP2pManager.START_WPS_FAILED,
WifiP2pManager.P2P_UNSUPPORTED);
break;
default:
case WifiP2pManager.START_LISTEN:
replyToMessage(message, WifiP2pManager.START_LISTEN_FAILED,
WifiP2pManager.P2P_UNSUPPORTED);
break;
case WifiP2pManager.STOP_LISTEN:
replyToMessage(message, WifiP2pManager.STOP_LISTEN_FAILED,
WifiP2pManager.P2P_UNSUPPORTED);
break;
default:
return NOT_HANDLED;
}
return HANDLED;
@@ -1022,6 +1035,35 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
case SET_MIRACAST_MODE:
mWifiNative.setMiracastMode(message.arg1);
break;
case WifiP2pManager.START_LISTEN:
if (DBG) logd(getName() + " start listen mode");
mWifiNative.p2pFlush();
if (mWifiNative.p2pExtListen(true, 500, 500)) {
replyToMessage(message, WifiP2pManager.START_LISTEN_SUCCEEDED);
} else {
replyToMessage(message, WifiP2pManager.START_LISTEN_FAILED);
}
break;
case WifiP2pManager.STOP_LISTEN:
if (DBG) logd(getName() + " stop listen mode");
if (mWifiNative.p2pExtListen(false, 0, 0)) {
replyToMessage(message, WifiP2pManager.STOP_LISTEN_SUCCEEDED);
} else {
replyToMessage(message, WifiP2pManager.STOP_LISTEN_FAILED);
}
mWifiNative.p2pFlush();
break;
case WifiP2pManager.SET_CHANNEL:
Bundle p2pChannels = (Bundle) message.obj;
int lc = p2pChannels.getInt("lc", 0);
int oc = p2pChannels.getInt("oc", 0);
if (DBG) logd(getName() + " set listen and operating channel");
if (mWifiNative.p2pSetChannel(lc, oc)) {
replyToMessage(message, WifiP2pManager.SET_CHANNEL_SUCCEEDED);
} else {
replyToMessage(message, WifiP2pManager.SET_CHANNEL_FAILED);
}
break;
default:
return NOT_HANDLED;
}
@@ -1171,6 +1213,35 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
mWifiNative.p2pGroupRemove(mGroup.getInterface());
}
break;
case WifiP2pManager.START_LISTEN:
if (DBG) logd(getName() + " start listen mode");
mWifiNative.p2pFlush();
if (mWifiNative.p2pExtListen(true, 500, 500)) {
replyToMessage(message, WifiP2pManager.START_LISTEN_SUCCEEDED);
} else {
replyToMessage(message, WifiP2pManager.START_LISTEN_FAILED);
}
break;
case WifiP2pManager.STOP_LISTEN:
if (DBG) logd(getName() + " stop listen mode");
if (mWifiNative.p2pExtListen(false, 0, 0)) {
replyToMessage(message, WifiP2pManager.STOP_LISTEN_SUCCEEDED);
} else {
replyToMessage(message, WifiP2pManager.STOP_LISTEN_FAILED);
}
mWifiNative.p2pFlush();
break;
case WifiP2pManager.SET_CHANNEL:
Bundle p2pChannels = (Bundle) message.obj;
int lc = p2pChannels.getInt("lc", 0);
int oc = p2pChannels.getInt("oc", 0);
if (DBG) logd(getName() + " set listen and operating channel");
if (mWifiNative.p2pSetChannel(lc, oc)) {
replyToMessage(message, WifiP2pManager.SET_CHANNEL_SUCCEEDED);
} else {
replyToMessage(message, WifiP2pManager.SET_CHANNEL_FAILED);
}
break;
default:
return NOT_HANDLED;
}