summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Quang Luong <qal@google.com> 2022-01-10 10:22:25 -0800
committer Quang Luong <qal@google.com> 2022-01-26 10:37:58 -0800
commitca3c5d996523d363da82b2215c4e4b8abcc414ad (patch)
treef2100d887d983b1282b98ae102744fdf331ffa2d
parenteaf49ae38e3d8f189f3aaa2f89688b499d5bbd19 (diff)
Plumb reply to P2P Invitation Received dialog back to framework
Plumb the reply to the P2P Invitation Recieved dialog back to the framework via @hide APIs. Bug: 209032090 Test: atest WifiDialogManagerTest, Tap on dialog from `adb shell cmd launch-dialog-p2p-invitation-received <ssid>` and verify WifiDialogManager log for dialog response. Change-Id: Id0792073fee71a0829f2178f47570de85d891a01
-rw-r--r--WifiDialog/src/com/android/wifi/dialog/WifiDialogActivity.java7
-rw-r--r--framework/java/android/net/wifi/BaseWifiService.java7
-rw-r--r--framework/java/android/net/wifi/IWifiManager.aidl2
-rw-r--r--framework/java/android/net/wifi/WifiManager.java22
-rw-r--r--service/java/com/android/server/wifi/WifiDialogManager.java65
-rw-r--r--service/java/com/android/server/wifi/WifiServiceImpl.java31
-rw-r--r--service/java/com/android/server/wifi/WifiShellCommand.java3
-rw-r--r--service/tests/wifitests/src/com/android/server/wifi/WifiDialogManagerTest.java147
-rw-r--r--service/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java3
9 files changed, 275 insertions, 12 deletions
diff --git a/WifiDialog/src/com/android/wifi/dialog/WifiDialogActivity.java b/WifiDialog/src/com/android/wifi/dialog/WifiDialogActivity.java
index dadebcc62f..409c08e2d0 100644
--- a/WifiDialog/src/com/android/wifi/dialog/WifiDialogActivity.java
+++ b/WifiDialog/src/com/android/wifi/dialog/WifiDialogActivity.java
@@ -327,28 +327,27 @@ public class WifiDialogActivity extends Activity {
Log.v(TAG, "P2P Invitation Received Dialog id=" + dialogId
+ " accepted with pin=" + pin);
}
- // TODO: Plumb this response to framework.
+ getWifiManager().replyToP2pInvitationReceivedDialog(dialogId, true, pin);
})
.setNegativeButton(getStringId("decline"), (dialogNegative, which) -> {
if (mIsVerboseLoggingEnabled) {
Log.v(TAG, "P2P Invitation Received dialog id=" + dialogId
+ " declined.");
}
- // TODO: Plumb this response to framework.
+ getWifiManager().replyToP2pInvitationReceivedDialog(dialogId, false, null);
})
.setOnCancelListener((dialogCancel) -> {
if (mIsVerboseLoggingEnabled) {
Log.v(TAG, "P2P Invitation Received dialog id=" + dialogId
+ " cancelled.");
}
- // TODO: Plumb this response to framework.
+ getWifiManager().replyToP2pInvitationReceivedDialog(dialogId, false, null);
})
.setOnDismissListener((dialogDismiss) -> {
if (mIsVerboseLoggingEnabled) {
Log.v(TAG, "P2P Invitation Received dialog id=" + dialogId
+ " dismissed.");
}
- // TODO: Plumb this response to framework.
removeIntentAndPossiblyFinish(dialogId);
})
.create();
diff --git a/framework/java/android/net/wifi/BaseWifiService.java b/framework/java/android/net/wifi/BaseWifiService.java
index b5d3160f78..61941595dd 100644
--- a/framework/java/android/net/wifi/BaseWifiService.java
+++ b/framework/java/android/net/wifi/BaseWifiService.java
@@ -854,5 +854,10 @@ public class BaseWifiService extends IWifiManager.Stub {
public void validateCurrentWifiMeetsAdminRequirements() {
throw new UnsupportedOperationException();
}
-}
+ @Override
+ public void replyToP2pInvitationReceivedDialog(
+ int dialogId, boolean accepted, @Nullable String optionalPin) {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/framework/java/android/net/wifi/IWifiManager.aidl b/framework/java/android/net/wifi/IWifiManager.aidl
index 5b346caece..ccac485178 100644
--- a/framework/java/android/net/wifi/IWifiManager.aidl
+++ b/framework/java/android/net/wifi/IWifiManager.aidl
@@ -374,4 +374,6 @@ interface IWifiManager
boolean setStaConcurrencyForMultiInternetMode(int mode);
void validateCurrentWifiMeetsAdminRequirements();
+
+ void replyToP2pInvitationReceivedDialog(int dialogId, boolean accepted, String optionalPin);
}
diff --git a/framework/java/android/net/wifi/WifiManager.java b/framework/java/android/net/wifi/WifiManager.java
index 36e3b79248..6b4fc9e362 100644
--- a/framework/java/android/net/wifi/WifiManager.java
+++ b/framework/java/android/net/wifi/WifiManager.java
@@ -9121,4 +9121,26 @@ public class WifiManager {
* @hide
*/
public static final String EXTRA_P2P_DISPLAY_PIN = "android.net.wifi.extra.P2P_DISPLAY_PIN";
+
+ /**
+ * Method for WifiDialog to notify the framework of a reply to a P2P Invitation Received dialog.
+ * @param dialogId id of the replying dialog.
+ * @param accepted Whether the invitation was accepted.
+ * @param optionalPin PIN of the reply, or {@code null} if none was supplied.
+ * @hide
+ */
+ public void replyToP2pInvitationReceivedDialog(
+ int dialogId, boolean accepted, @Nullable String optionalPin) {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "notifyP2pInvitationResponse: "
+ + "dialogId=" + dialogId
+ + ", accepted=" + accepted
+ + ", pin=" + optionalPin);
+ }
+ try {
+ mService.replyToP2pInvitationReceivedDialog(dialogId, accepted, optionalPin);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/service/java/com/android/server/wifi/WifiDialogManager.java b/service/java/com/android/server/wifi/WifiDialogManager.java
index 5adf96709a..a00d47f0b5 100644
--- a/service/java/com/android/server/wifi/WifiDialogManager.java
+++ b/service/java/com/android/server/wifi/WifiDialogManager.java
@@ -21,12 +21,15 @@ import android.content.pm.PackageManager;
import android.net.wifi.WifiContext;
import android.net.wifi.WifiManager;
import android.os.UserHandle;
+import android.util.ArraySet;
import android.util.Log;
import android.util.SparseArray;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import java.util.Set;
+
/**
* Class to manage launching dialogs via WifiDialog and returning the user reply.
*/
@@ -38,8 +41,11 @@ public class WifiDialogManager {
private boolean mVerboseLoggingEnabled;
private int mNextDialogId = 0;
+ private Set<Integer> mCurrentDialogIds = new ArraySet<>();
private @NonNull SparseArray<P2pInvitationReceivedDialogCallback>
mP2pInvitationReceivedDialogCallbacks = new SparseArray<>();
+ private @NonNull SparseArray<WifiThreadRunner>
+ mP2pInvitationReceivedDialogThreadRunners = new SparseArray<>();
@NonNull WifiContext mContext;
@NonNull PackageManager mPackageManager;
@@ -57,7 +63,7 @@ public class WifiDialogManager {
}
private int getNextDialogId() {
- if (mNextDialogId < 0) {
+ if (mCurrentDialogIds.isEmpty() || mNextDialogId < 0) {
mNextDialogId = 0;
}
return mNextDialogId++;
@@ -84,19 +90,26 @@ public class WifiDialogManager {
* @param deviceName Name of the device sending the invitation.
* @param isPinRequested True if a PIN was requested and a PIN input UI should be shown.
* @param displayPin Display PIN, or {@code null} if no PIN should be displayed
- * @param callback Callback to receive the dialog response. Runs on the main Wi-Fi thread.
+ * @param callback Callback to receive the dialog response.
+ * @param threadRunner WifiThreadRunner to run the callback on.
* @return id of the launched dialog, or {@code -1} if the dialog could not be created.
*/
public int launchP2pInvitationReceivedDialog(
String deviceName,
boolean isPinRequested,
@Nullable String displayPin,
- @NonNull P2pInvitationReceivedDialogCallback callback) {
+ @NonNull P2pInvitationReceivedDialogCallback callback,
+ @NonNull WifiThreadRunner threadRunner) {
if (callback == null) {
Log.e(TAG, "Cannot launch a P2P Invitation Received dialog with null callback!");
return -1;
}
+ if (callback == null) {
+ Log.e(TAG, "Cannot launch a P2P Invitation Received dialog with null handler!");
+ return -1;
+ }
int dialogId = getNextDialogId();
+ mCurrentDialogIds.add(dialogId);
Intent intent = new Intent();
String wifiDialogApkPkgName = mContext.getWifiDialogApkPkgName();
if (wifiDialogApkPkgName == null) {
@@ -113,6 +126,7 @@ public class WifiDialogManager {
intent.putExtra(WifiManager.EXTRA_P2P_DISPLAY_PIN, displayPin);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mP2pInvitationReceivedDialogCallbacks.put(dialogId, callback);
+ mP2pInvitationReceivedDialogThreadRunners.put(dialogId, threadRunner);
mContext.startActivityAsUser(intent, UserHandle.CURRENT);
if (mVerboseLoggingEnabled) {
Log.v(TAG, "Launching P2P Invitation Received dialog."
@@ -124,4 +138,49 @@ public class WifiDialogManager {
}
return dialogId;
}
+
+ /**
+ * Returns the reply to a P2P Invitation Received dialog to the callback of matching dialogId.
+ * @param dialogId id of the replying dialog.
+ * @param accepted Whether the invitation was accepted.
+ * @param optionalPin PIN of the reply, or {@code null} if none was supplied.
+ * @hide
+ */
+ public void replyToP2pInvitationReceivedDialog(
+ final int dialogId, final boolean accepted, final @Nullable String optionalPin) {
+ if (mVerboseLoggingEnabled) {
+ Log.i(TAG, "Response received for P2P Invitation Received dialog."
+ + " id=" + dialogId
+ + " accepted=" + accepted
+ + " pin=" + optionalPin);
+ }
+ mCurrentDialogIds.remove(dialogId);
+ final P2pInvitationReceivedDialogCallback callback =
+ mP2pInvitationReceivedDialogCallbacks.get(dialogId);
+ mP2pInvitationReceivedDialogCallbacks.remove(dialogId);
+ if (callback == null) {
+ if (mVerboseLoggingEnabled) {
+ Log.w(TAG, "No matching callback for P2P Invitation Received dialog"
+ + " id=" + dialogId);
+ }
+ return;
+ }
+ final WifiThreadRunner threadRunner =
+ mP2pInvitationReceivedDialogThreadRunners.get(dialogId);
+ mP2pInvitationReceivedDialogThreadRunners.remove(dialogId);
+ if (threadRunner == null) {
+ if (mVerboseLoggingEnabled) {
+ Log.w(TAG, "No matching handler for P2P Invitation Received dialog"
+ + " id=" + dialogId);
+ }
+ return;
+ }
+ threadRunner.post(() -> {
+ if (accepted) {
+ callback.onAccepted(optionalPin);
+ } else {
+ callback.onDeclined();
+ }
+ });
+ }
}
diff --git a/service/java/com/android/server/wifi/WifiServiceImpl.java b/service/java/com/android/server/wifi/WifiServiceImpl.java
index 228ffc69ab..e010a8d989 100644
--- a/service/java/com/android/server/wifi/WifiServiceImpl.java
+++ b/service/java/com/android/server/wifi/WifiServiceImpl.java
@@ -92,6 +92,7 @@ import android.net.wifi.WifiAnnotations.WifiStandard;
import android.net.wifi.WifiAvailableChannel;
import android.net.wifi.WifiClient;
import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiContext;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiManager.AddNetworkResult;
@@ -204,7 +205,7 @@ public class WifiServiceImpl extends BaseWifiService {
private final ActiveModeWarden mActiveModeWarden;
private final ScanRequestProxy mScanRequestProxy;
- private final Context mContext;
+ private final WifiContext mContext;
private final FrameworkFacade mFacade;
private final Clock mClock;
@@ -306,6 +307,7 @@ public class WifiServiceImpl extends BaseWifiService {
private final SimRequiredNotifier mSimRequiredNotifier;
private final MakeBeforeBreakManager mMakeBeforeBreakManager;
private final LastCallerInfoManager mLastCallerInfoManager;
+ private final @NonNull WifiDialogManager mWifiDialogManager;
private boolean mWifiTetheringDisallowed;
private boolean mIsBootComplete;
@@ -427,7 +429,7 @@ public class WifiServiceImpl extends BaseWifiService {
}
- public WifiServiceImpl(Context context, WifiInjector wifiInjector) {
+ public WifiServiceImpl(WifiContext context, WifiInjector wifiInjector) {
mContext = context;
mWifiInjector = wifiInjector;
mClock = wifiInjector.getClock();
@@ -475,6 +477,7 @@ public class WifiServiceImpl extends BaseWifiService {
mWifiCarrierInfoManager = wifiInjector.getWifiCarrierInfoManager();
mMakeBeforeBreakManager = mWifiInjector.getMakeBeforeBreakManager();
mLastCallerInfoManager = mWifiInjector.getLastCallerInfoManager();
+ mWifiDialogManager = mWifiInjector.getWifiDialogManager();
mBuildProperties = mWifiInjector.getBuildProperties();
mDefaultClientModeManager = mWifiInjector.getDefaultClientModeManager();
mCountryCodeTracker = new CountryCodeTracker();
@@ -6380,4 +6383,28 @@ public class WifiServiceImpl extends BaseWifiService {
}
});
}
+
+ /**
+ * Method for WifiDialog to notify the framework of a reply to a P2P Invitation Received dialog.
+ * @param dialogId id of the replying dialog.
+ * @param accepted Whether the invitation was accepted.
+ * @param optionalPin PIN of the reply, or {@code null} if none was supplied.
+ */
+ @Override
+ public void replyToP2pInvitationReceivedDialog(
+ int dialogId, boolean accepted, @Nullable String optionalPin) {
+ int uid = Binder.getCallingUid();
+ int pid = Binder.getCallingPid();
+ mWifiPermissionsUtil.checkPackage(uid, mContext.getWifiDialogApkPkgName());
+ if (isVerboseLoggingEnabled()) {
+ mLog.info("replyToP2pInvitationReceivedDialog uid=% pid=%"
+ + " dialogId=% accepted=% optionalPin=%")
+ .c(uid).c(pid).c(dialogId).c(accepted).c(optionalPin)
+ .flush();
+ }
+ mWifiThreadRunner.post(() ->
+ mWifiDialogManager.replyToP2pInvitationReceivedDialog(
+ dialogId, accepted, optionalPin)
+ );
+ }
}
diff --git a/service/java/com/android/server/wifi/WifiShellCommand.java b/service/java/com/android/server/wifi/WifiShellCommand.java
index fe0aae408a..4dba1b1f4a 100644
--- a/service/java/com/android/server/wifi/WifiShellCommand.java
+++ b/service/java/com/android/server/wifi/WifiShellCommand.java
@@ -1171,7 +1171,8 @@ public class WifiShellCommand extends BasicShellCommandHandler {
deviceName,
isPinRequested,
displayPin,
- callback);
+ callback,
+ mWifiThreadRunner);
pw.println("Launched dialog. Waiting up to 15 seconds for user response.");
pw.flush();
String msg = queue.poll(15, TimeUnit.SECONDS);
diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiDialogManagerTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiDialogManagerTest.java
new file mode 100644
index 0000000000..3401de1171
--- /dev/null
+++ b/service/tests/wifitests/src/com/android/server/wifi/WifiDialogManagerTest.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2022 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 com.android.server.wifi;
+
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.net.wifi.WifiContext;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Unit tests for {@link WifiDialogManager}.
+ */
+@SmallTest
+public class WifiDialogManagerTest extends WifiBaseTest {
+
+ @Mock WifiContext mWifiContext;
+ @Mock WifiThreadRunner mCallbackThreadRunner;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ when(mWifiContext.getWifiDialogApkPkgName()).thenReturn("WifiDialogApkPkgName");
+ when(mCallbackThreadRunner.post(any(Runnable.class))).then(i -> {
+ ((Runnable) i.getArguments()[0]).run();
+ return true;
+ });
+ }
+
+ /**
+ * Verifies that launching a P2P Invitation Received dialog with a callback will result in the
+ * correct callback methods invoked when a response is received.
+ */
+ @Test
+ public void testP2pInvitationReceivedDialog_launchAndResponse_notifiesCallback() {
+ WifiDialogManager wifiDialogManager = new WifiDialogManager(mWifiContext);
+ WifiDialogManager.P2pInvitationReceivedDialogCallback callback =
+ mock(WifiDialogManager.P2pInvitationReceivedDialogCallback.class);
+ int dialogId;
+
+ // Accept without PIN
+ dialogId = wifiDialogManager.launchP2pInvitationReceivedDialog(
+ "deviceName", false, null, callback, mCallbackThreadRunner);
+ wifiDialogManager.replyToP2pInvitationReceivedDialog(dialogId, true, null);
+ verify(callback, times(1)).onAccepted(null);
+
+ // Callback should be removed from callback list, so a second notification should be ignored
+ wifiDialogManager.replyToP2pInvitationReceivedDialog(dialogId, true, "012345");
+ verify(callback, times(0)).onAccepted("012345");
+
+ // Accept with PIN
+ dialogId = wifiDialogManager.launchP2pInvitationReceivedDialog(
+ "deviceName", true, null, callback, mCallbackThreadRunner);
+ wifiDialogManager.replyToP2pInvitationReceivedDialog(dialogId, true, "012345");
+ verify(callback, times(1)).onAccepted("012345");
+
+ // Accept with PIN but PIN was not requested
+ dialogId = wifiDialogManager.launchP2pInvitationReceivedDialog(
+ "deviceName", false, null, callback, mCallbackThreadRunner);
+ wifiDialogManager.replyToP2pInvitationReceivedDialog(dialogId, true, "012345");
+ verify(callback, times(2)).onAccepted("012345");
+
+ // Accept without PIN but PIN was requested
+ dialogId = wifiDialogManager.launchP2pInvitationReceivedDialog(
+ "deviceName", true, null, callback, mCallbackThreadRunner);
+ wifiDialogManager.replyToP2pInvitationReceivedDialog(dialogId, true, null);
+ verify(callback, times(2)).onAccepted(null);
+
+ // Decline without PIN
+ dialogId = wifiDialogManager.launchP2pInvitationReceivedDialog(
+ "deviceName", false, null, callback, mCallbackThreadRunner);
+ wifiDialogManager.replyToP2pInvitationReceivedDialog(dialogId, false, null);
+ verify(callback, times(1)).onDeclined();
+
+ // Decline with PIN
+ dialogId = wifiDialogManager.launchP2pInvitationReceivedDialog(
+ "deviceName", true, null, callback, mCallbackThreadRunner);
+ wifiDialogManager.replyToP2pInvitationReceivedDialog(dialogId, false, "012345");
+ verify(callback, times(2)).onDeclined();
+
+ // Decline with PIN but PIN was not requested
+ dialogId = wifiDialogManager.launchP2pInvitationReceivedDialog(
+ "deviceName", false, null, callback, mCallbackThreadRunner);
+ wifiDialogManager.replyToP2pInvitationReceivedDialog(dialogId, false, "012345");
+ verify(callback, times(3)).onDeclined();
+
+ // Decline without PIN but PIN was requested
+ dialogId = wifiDialogManager.launchP2pInvitationReceivedDialog(
+ "deviceName", true, null, callback, mCallbackThreadRunner);
+ wifiDialogManager.replyToP2pInvitationReceivedDialog(dialogId, false, null);
+ verify(callback, times(4)).onDeclined();
+ }
+
+ /**
+ * Verifies the right callback is notified for a response to a P2P Invitation Received dialog.
+ */
+ @Test
+ public void testP2pInvitationReceivedDialog_multipleDialogs_responseMatchedToCorrectCallback() {
+ WifiDialogManager wifiDialogManager = new WifiDialogManager(mWifiContext);
+
+ // Launch Dialog1
+ WifiDialogManager.P2pInvitationReceivedDialogCallback callback1 = mock(
+ WifiDialogManager.P2pInvitationReceivedDialogCallback.class);
+ int dialogId1 = wifiDialogManager.launchP2pInvitationReceivedDialog(
+ "deviceName", false, null, callback1, mCallbackThreadRunner);
+
+ // Launch Dialog2
+ WifiDialogManager.P2pInvitationReceivedDialogCallback callback2 = mock(
+ WifiDialogManager.P2pInvitationReceivedDialogCallback.class);
+ int dialogId2 = wifiDialogManager.launchP2pInvitationReceivedDialog(
+ "deviceName", false, null, callback2, mCallbackThreadRunner);
+
+ // callback1 notified
+ wifiDialogManager.replyToP2pInvitationReceivedDialog(dialogId1, true, null);
+ verify(callback1, times(1)).onAccepted(null);
+ verify(callback2, times(0)).onAccepted(null);
+
+ // callback2 notified
+ wifiDialogManager.replyToP2pInvitationReceivedDialog(dialogId2, true, null);
+ verify(callback1, times(1)).onAccepted(null);
+ verify(callback2, times(1)).onAccepted(null);
+ }
+}
diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java
index 86980d0032..e23559c19c 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java
@@ -147,6 +147,7 @@ import android.net.wifi.SoftApInfo;
import android.net.wifi.WifiClient;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiConfiguration.KeyMgmt;
+import android.net.wifi.WifiContext;
import android.net.wifi.WifiEnterpriseConfig;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
@@ -313,7 +314,7 @@ public class WifiServiceImplTest extends WifiBaseTest {
ArgumentCaptor.forClass(SoftApModeConfiguration.class);
@Mock Bundle mBundle;
- @Mock Context mContext;
+ @Mock WifiContext mContext;
@Mock Context mContextAsUser;
@Mock WifiInjector mWifiInjector;
@Mock WifiCountryCode mWifiCountryCode;