summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/android/hardware/display/DisplayManager.java10
-rw-r--r--core/java/android/hardware/display/DisplayManagerGlobal.java16
-rw-r--r--core/java/android/hardware/display/IDisplayManager.aidl6
-rw-r--r--core/java/android/hardware/display/WifiDisplaySessionInfo.java116
-rw-r--r--core/java/android/hardware/display/WifiDisplayStatus.java28
-rw-r--r--core/java/android/provider/Settings.java8
-rw-r--r--core/jni/android_media_RemoteDisplay.cpp28
-rw-r--r--media/java/android/media/RemoteDisplay.java17
-rw-r--r--services/java/com/android/server/display/DisplayManagerService.java42
-rw-r--r--services/java/com/android/server/display/WifiDisplayAdapter.java42
-rw-r--r--services/java/com/android/server/display/WifiDisplayController.java90
-rw-r--r--wifi/java/android/net/wifi/WifiNative.java31
-rw-r--r--wifi/java/android/net/wifi/p2p/WifiP2pManager.java45
-rw-r--r--wifi/java/android/net/wifi/p2p/WifiP2pService.java73
14 files changed, 535 insertions, 17 deletions
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 7d65736..0071865 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -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.
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 10c14ff..936a086 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -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();
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index afaf436..6b2c887 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -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();
}
diff --git a/core/java/android/hardware/display/WifiDisplaySessionInfo.java b/core/java/android/hardware/display/WifiDisplaySessionInfo.java
new file mode 100644
index 0000000..33d2725
--- /dev/null
+++ b/core/java/android/hardware/display/WifiDisplaySessionInfo.java
@@ -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
+ ;
+ }
+}
diff --git a/core/java/android/hardware/display/WifiDisplayStatus.java b/core/java/android/hardware/display/WifiDisplayStatus.java
index 77acdc0..5216727 100644
--- a/core/java/android/hardware/display/WifiDisplayStatus.java
+++ b/core/java/android/hardware/display/WifiDisplayStatus.java
@@ -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
+ "}";
}
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index b3309e1..0b51b8a 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5075,6 +5075,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>
* If not connected and the scan results have an open network, we will
diff --git a/core/jni/android_media_RemoteDisplay.cpp b/core/jni/android_media_RemoteDisplay.cpp
index 80d13be..3fd8ed9 100644
--- a/core/jni/android_media_RemoteDisplay.cpp
+++ b/core/jni/android_media_RemoteDisplay.cpp
@@ -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 =
diff --git a/media/java/android/media/RemoteDisplay.java b/media/java/android/media/RemoteDisplay.java
index b463d26..7afce1a 100644
--- a/media/java/android/media/RemoteDisplay.java
+++ b/media/java/android/media/RemoteDisplay.java
@@ -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);
}
diff --git a/services/java/com/android/server/display/DisplayManagerService.java b/services/java/com/android/server/display/DisplayManagerService.java
index 659163c..249c8b0 100644
--- a/services/java/com/android/server/display/DisplayManagerService.java
+++ b/services/java/com/android/server/display/DisplayManagerService.java
@@ -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();
diff --git a/services/java/com/android/server/display/WifiDisplayAdapter.java b/services/java/com/android/server/display/WifiDisplayAdapter.java
index a9da30f..f7bbdf8 100644
--- a/services/java/com/android/server/display/WifiDisplayAdapter.java
+++ b/services/java/com/android/server/display/WifiDisplayAdapter.java
@@ -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) {
@@ -580,6 +612,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()) {
display = mPersistentDataStore.applyWifiDisplayAlias(display);
diff --git a/services/java/com/android/server/display/WifiDisplayController.java b/services/java/com/android/server/display/WifiDisplayController.java
index 846a74d..cd201f5 100644
--- a/services/java/com/android/server/display/WifiDisplayController.java
+++ b/services/java/com/android/server/display/WifiDisplayController.java
@@ -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,8 +691,29 @@ 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) {
@@ -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();
}
}
diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java
index 79c1163..d3342dd 100644
--- a/wifi/java/android/net/wifi/WifiNative.java
+++ b/wifi/java/android/net/wifi/WifiNative.java
@@ -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");
}
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
index 737ab91..4988b92 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -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.
*
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pService.java b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
index 63b94a2..05196b8 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pService.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
@@ -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;
}