diff options
5 files changed, 108 insertions, 4 deletions
diff --git a/service/java/com/android/server/wifi/WifiMetrics.java b/service/java/com/android/server/wifi/WifiMetrics.java index ca2e90552..f61723643 100644 --- a/service/java/com/android/server/wifi/WifiMetrics.java +++ b/service/java/com/android/server/wifi/WifiMetrics.java @@ -88,6 +88,7 @@ import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiLockStats; import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiNetworkRequestApiLog; import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiNetworkSuggestionApiLog; import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiNetworkSuggestionApiLog.SuggestionAppCount; +import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiNetworkSuggestionApiLog.UserReaction; import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiToggleStats; import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiUsabilityStats; import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiUsabilityStatsEntry; @@ -416,6 +417,9 @@ public class WifiMetrics { private final IntHistogram mWifiNetworkSuggestionApiListSizeHistogram = new IntHistogram(NETWORK_SUGGESTION_API_LIST_SIZE_HISTOGRAM_BUCKETS); private final IntCounter mWifiNetworkSuggestionApiAppTypeCounter = new IntCounter(); + private final List<UserReaction> mWifiNetworkSuggestionUserApprovalAppUiReaction = + new ArrayList<>(); + private final WifiLockStats mWifiLockStats = new WifiLockStats(); private static final int[] WIFI_LOCK_SESSION_DURATION_HISTOGRAM_BUCKETS = {1, 10, 60, 600, 3600}; @@ -3581,6 +3585,7 @@ public class WifiMetrics { + mWifiNetworkSuggestionApiListSizeHistogram); pw.println("mWifiNetworkSuggestionApiAppTypeCounter:\n" + mWifiNetworkSuggestionApiAppTypeCounter); + printSuggestionUserApprovalAppReaction(pw); pw.println("mNetworkIdToNominatorId:\n" + mNetworkIdToNominatorId); pw.println("mWifiLockStats:\n" + mWifiLockStats); pw.println("mWifiLockHighPerfAcqDurationSecHistogram:\n" @@ -3687,6 +3692,13 @@ public class WifiMetrics { pw.println(line.toString()); } + private void printSuggestionUserApprovalAppReaction(PrintWriter pw) { + pw.println("mWifiNetworkSuggestionApprovalAppUiUserReaction:"); + for (UserReaction event : mWifiNetworkSuggestionUserApprovalAppUiReaction) { + pw.println(event); + } + } + /** * Update various counts of saved network types * @param networks List of WifiConfigurations representing all saved networks, must not be null @@ -4205,6 +4217,9 @@ public class WifiMetrics { entry.count = count; return entry; }); + mWifiNetworkSuggestionApiLog.userApprovalAppUiReaction = + mWifiNetworkSuggestionUserApprovalAppUiReaction + .toArray(new UserReaction[0]); mWifiLogProto.wifiNetworkSuggestionApiLog = mWifiNetworkSuggestionApiLog; mWifiLockStats.highPerfLockAcqDurationSecHistogram = @@ -4468,10 +4483,10 @@ public class WifiMetrics { mLinkProbeStaEventCount = 0; mNetworkSelectionExperimentPairNumChoicesCounts.clear(); mWifiNetworkSuggestionApiLog.clear(); - mWifiNetworkSuggestionApiLog.clear(); mWifiNetworkRequestApiMatchSizeHistogram.clear(); mWifiNetworkSuggestionApiListSizeHistogram.clear(); mWifiNetworkSuggestionApiAppTypeCounter.clear(); + mWifiNetworkSuggestionUserApprovalAppUiReaction.clear(); mWifiLockHighPerfAcqDurationSecHistogram.clear(); mWifiLockLowLatencyAcqDurationSecHistogram.clear(); mWifiLockHighPerfActiveSessionDurationSecHistogram.clear(); @@ -5948,10 +5963,33 @@ public class WifiMetrics { default: typeCode = WifiNetworkSuggestionApiLog.TYPE_UNKNOWN; } + mWifiNetworkSuggestionApiAppTypeCounter.increment(typeCode); } - mWifiNetworkSuggestionApiAppTypeCounter.increment(typeCode); } + /** Add user action to the approval app UI */ + public void addNetworkSuggestionUserApprovalAppUiReaction(int actionType, boolean isDialog) { + int actionCode; + UserReaction event = new UserReaction(); + synchronized (mLock) { + switch (actionType) { + case WifiNetworkSuggestionsManager.ACTION_USER_ALLOWED_APP: + actionCode = WifiNetworkSuggestionApiLog.ACTION_ALLOWED; + break; + case WifiNetworkSuggestionsManager.ACTION_USER_DISALLOWED_APP: + actionCode = WifiNetworkSuggestionApiLog.ACTION_DISALLOWED; + break; + case WifiNetworkSuggestionsManager.ACTION_USER_DISMISS: + actionCode = WifiNetworkSuggestionApiLog.ACTION_DISMISS; + break; + default: + actionCode = WifiNetworkSuggestionApiLog.ACTION_UNKNOWN; + } + event.userAction = actionCode; + event.isDialog = isDialog; + mWifiNetworkSuggestionUserApprovalAppUiReaction.add(event); + } + } /** * Sets the nominator for a network (i.e. which entity made the suggestion to connect) * @param networkId the ID of the network, from its {@link WifiConfiguration} diff --git a/service/java/com/android/server/wifi/WifiNetworkSuggestionsManager.java b/service/java/com/android/server/wifi/WifiNetworkSuggestionsManager.java index 8eb5a337a..516c89ecc 100644 --- a/service/java/com/android/server/wifi/WifiNetworkSuggestionsManager.java +++ b/service/java/com/android/server/wifi/WifiNetworkSuggestionsManager.java @@ -109,6 +109,10 @@ public class WifiNetworkSuggestionsManager { public static final int APP_TYPE_NETWORK_PROVISIONING = 2; public static final int APP_TYPE_NON_PRIVILEGED = 3; + public static final int ACTION_USER_ALLOWED_APP = 1; + public static final int ACTION_USER_DISALLOWED_APP = 2; + public static final int ACTION_USER_DISMISS = 3; + /** * Limit number of hidden networks attach to scan */ @@ -372,6 +376,8 @@ public class WifiNetworkSuggestionsManager { */ private boolean mUserApprovalUiActive = false; + private boolean mIsLastUserApprovalUiDialog = false; + private boolean mUserDataLoaded = false; /** * Listener for app-ops changes for active suggestor apps. @@ -482,6 +488,9 @@ public class WifiNetworkSuggestionsManager { // Set the user approved flag. setHasUserApprovedForApp(true, packageName); mUserApprovalUiActive = false; + mWifiMetrics.addNetworkSuggestionUserApprovalAppUiReaction( + ACTION_USER_ALLOWED_APP, + mIsLastUserApprovalUiDialog); } private void handleUserDisallowAction(int uid, String packageName) { @@ -492,11 +501,17 @@ public class WifiNetworkSuggestionsManager { mAppOps.setMode(AppOpsManager.OPSTR_CHANGE_WIFI_STATE, uid, packageName, MODE_IGNORED); mUserApprovalUiActive = false; + mWifiMetrics.addNetworkSuggestionUserApprovalAppUiReaction( + ACTION_USER_DISALLOWED_APP, + mIsLastUserApprovalUiDialog); } private void handleUserDismissAction() { Log.i(TAG, "User dismissed the notification"); mUserApprovalUiActive = false; + mWifiMetrics.addNetworkSuggestionUserApprovalAppUiReaction( + ACTION_USER_DISMISS, + mIsLastUserApprovalUiDialog); } private final BroadcastReceiver mBroadcastReceiver = @@ -853,7 +868,7 @@ public class WifiNetworkSuggestionsManager { if (isSuggestionFromForegroundApp(packageName)) { sendUserApprovalDialog(packageName, uid); } else { - sendUserApprovalNotification(packageName, uid); + sendUserApprovalNotificationIfNotApproved(packageName, uid); } mWifiMetrics.incrementNetworkSuggestionApiUsageNumOfAppInType( APP_TYPE_NON_PRIVILEGED); @@ -1318,6 +1333,7 @@ public class WifiNetworkSuggestionsManager { WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS); dialog.show(); mUserApprovalUiActive = true; + mIsLastUserApprovalUiDialog = true; } private void sendUserApprovalNotification(@NonNull String packageName, int uid) { @@ -1359,6 +1375,7 @@ public class WifiNetworkSuggestionsManager { mNotificationManager.notify( SystemMessage.NOTE_NETWORK_SUGGESTION_AVAILABLE, notification); mUserApprovalUiActive = true; + mIsLastUserApprovalUiDialog = false; } /** diff --git a/service/proto/src/metrics.proto b/service/proto/src/metrics.proto index c57101f06..9a33aafcc 100644 --- a/service/proto/src/metrics.proto +++ b/service/proto/src/metrics.proto @@ -2892,6 +2892,16 @@ message WifiNetworkSuggestionApiLog { // Suggestion app without special privilege. TYPE_NON_PRIVILEGED = 3; } + enum UserActionCode { + // UNKNOWN user action. + ACTION_UNKNOWN = 0; + // Action user allowed. + ACTION_ALLOWED = 1; + // Action user disallowed. + ACTION_DISALLOWED = 2; + // Action user dismiss. + ACTION_DISMISS = 3; + } message SuggestionAppCount { // Suggestion app type. @@ -2900,6 +2910,13 @@ message WifiNetworkSuggestionApiLog { optional int32 count = 2; } + message UserReaction { + // User action to the UI. + optional UserActionCode user_action = 1; + // Is UI a dialog or notification. + optional bool is_dialog = 3; + } + // Number of modifications to their suggestions by apps. optional int32 num_modification = 1; @@ -2914,6 +2931,9 @@ message WifiNetworkSuggestionApiLog { // Count of app using suggestion API with different privilege. repeated SuggestionAppCount app_count_per_type = 5; + + // Event of user reaction to the UI. + repeated UserReaction user_approval_app_ui_reaction = 6; } // WifiLock metrics diff --git a/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java b/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java index d2c292221..6506bd8d2 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java @@ -4177,6 +4177,9 @@ public class WifiMetricsTest extends WifiBaseTest { add(60); }}); + mWifiMetrics.addNetworkSuggestionUserApprovalAppUiReaction(1, true); + mWifiMetrics.addNetworkSuggestionUserApprovalAppUiReaction(2, false); + dumpProtoAndDeserialize(); assertEquals(4, mDecodedProto.wifiNetworkSuggestionApiLog.numModification); @@ -4202,6 +4205,21 @@ public class WifiMetricsTest extends WifiBaseTest { assertEquals(WifiMetricsProto.WifiNetworkSuggestionApiLog.TYPE_NON_PRIVILEGED, mDecodedProto.wifiNetworkSuggestionApiLog.appCountPerType[2].appType); assertEquals(3, mDecodedProto.wifiNetworkSuggestionApiLog.appCountPerType[2].count); + + assertEquals(2, + mDecodedProto.wifiNetworkSuggestionApiLog.userApprovalAppUiReaction.length); + assertEquals(WifiMetricsProto.WifiNetworkSuggestionApiLog.ACTION_ALLOWED, + mDecodedProto.wifiNetworkSuggestionApiLog.userApprovalAppUiReaction[0] + .userAction); + assertEquals(true, + mDecodedProto.wifiNetworkSuggestionApiLog.userApprovalAppUiReaction[0] + .isDialog); + assertEquals(WifiMetricsProto.WifiNetworkSuggestionApiLog.ACTION_DISALLOWED, + mDecodedProto.wifiNetworkSuggestionApiLog.userApprovalAppUiReaction[1] + .userAction); + assertEquals(false, + mDecodedProto.wifiNetworkSuggestionApiLog.userApprovalAppUiReaction[1] + .isDialog); } private NetworkSelectionExperimentDecisions findUniqueNetworkSelectionExperimentDecisions( diff --git a/tests/wifitests/src/com/android/server/wifi/WifiNetworkSuggestionsManagerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiNetworkSuggestionsManagerTest.java index f2f9c8ad4..df729bfb1 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiNetworkSuggestionsManagerTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiNetworkSuggestionsManagerTest.java @@ -2269,7 +2269,8 @@ public class WifiNetworkSuggestionsManagerTest extends WifiBaseTest { sendBroadcastForUserActionOnApp( NOTIFICATION_USER_DISMISSED_INTENT_ACTION, TEST_PACKAGE_1, TEST_UID_1); reset(mNotificationManger); - + verify(mWifiMetrics).addNetworkSuggestionUserApprovalAppUiReaction( + WifiNetworkSuggestionsManager.ACTION_USER_DISMISS, false); // Simulate finding the network in scan results. mWifiNetworkSuggestionsManager.getNetworkSuggestionsForScanDetail( createScanDetailForNetwork(networkSuggestion.wifiConfiguration)); @@ -2326,6 +2327,8 @@ public class WifiNetworkSuggestionsManagerTest extends WifiBaseTest { // Verify config store interactions. verify(mWifiConfigManager, times(2)).saveToStore(true); assertTrue(mDataSource.hasNewDataToSerialize()); + verify(mWifiMetrics).addNetworkSuggestionUserApprovalAppUiReaction( + WifiNetworkSuggestionsManager.ACTION_USER_ALLOWED_APP, false); reset(mNotificationManger); // We should not resend the notification next time the network is found in scan results. @@ -2376,6 +2379,8 @@ public class WifiNetworkSuggestionsManagerTest extends WifiBaseTest { // Verify config store interactions. verify(mWifiConfigManager, times(2)).saveToStore(true); assertTrue(mDataSource.hasNewDataToSerialize()); + verify(mWifiMetrics).addNetworkSuggestionUserApprovalAppUiReaction( + WifiNetworkSuggestionsManager.ACTION_USER_DISALLOWED_APP, false); reset(mNotificationManger); @@ -2544,6 +2549,8 @@ public class WifiNetworkSuggestionsManagerTest extends WifiBaseTest { // Verify config store interactions. verify(mWifiConfigManager, times(2)).saveToStore(true); assertTrue(mDataSource.hasNewDataToSerialize()); + verify(mWifiMetrics).addNetworkSuggestionUserApprovalAppUiReaction( + WifiNetworkSuggestionsManager.ACTION_USER_ALLOWED_APP, true); // We should not resend the notification next time the network is found in scan results. mWifiNetworkSuggestionsManager.getNetworkSuggestionsForScanDetail( @@ -2588,6 +2595,8 @@ public class WifiNetworkSuggestionsManagerTest extends WifiBaseTest { // Verify config store interactions. verify(mWifiConfigManager, times(2)).saveToStore(true); assertTrue(mDataSource.hasNewDataToSerialize()); + verify(mWifiMetrics).addNetworkSuggestionUserApprovalAppUiReaction( + WifiNetworkSuggestionsManager.ACTION_USER_DISALLOWED_APP, true); // Now trigger the app-ops callback to ensure we remove all of their suggestions. AppOpsManager.OnOpChangedListener listener = mAppOpChangedListenerCaptor.getValue(); @@ -2640,6 +2649,8 @@ public class WifiNetworkSuggestionsManagerTest extends WifiBaseTest { // Verify no new config store or app-op interactions. verify(mWifiConfigManager).saveToStore(true); // 1 already done for add verify(mAppOpsManager, never()).setMode(any(), anyInt(), any(), anyInt()); + verify(mWifiMetrics).addNetworkSuggestionUserApprovalAppUiReaction( + WifiNetworkSuggestionsManager.ACTION_USER_DISMISS, true); // We should resend the notification next time the network is found in scan results. mWifiNetworkSuggestionsManager.getNetworkSuggestionsForScanDetail( |