Fix automatically directing the user to the captive portal in Wi-Fi Slice
The feature failed after the CL "Force the adapter to rebind cards with a toggle". Because toggle slices have been forced to rebind after starting another activity and when any slice is updating. This unpins Wi-Fi slice and stops WifiScanWorker and then clears the saved clicked network. Solution: 1. Change ConnectToWifiHandler from activity to receiver and send broadcasts to it with FLAG_RECEIVER_FOREGROUND, so Wi-Fi slice won't be forced to rebind. 2. Seperate Wi-Fi scan worker and contextual Wi-Fi scan worker. Keep the original logic for the generic one, and then add the logic below to the contextual one. 3. Do not clear the saved clicked network when slice is unppined because it happens frequently in contextual homepage. 4. Introduce a static long in ContextualWifiScanWorker that updates once in every visible UI session. A session is when the screen is visible to user. 5. Use session token to determine whether auto-starting captive portal is needed. Fixes: 128056349 Test: robotest, visual in homepage and network panel Change-Id: I9e03c379806e124fa7253b2a635574b2433f6afc
This commit is contained in:
@@ -16,7 +16,9 @@
|
||||
|
||||
package com.android.settings.wifi.slice;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.Network;
|
||||
import android.net.wifi.WifiManager;
|
||||
@@ -30,35 +32,36 @@ import com.android.settings.wifi.WifiUtils;
|
||||
import com.android.settingslib.wifi.AccessPoint;
|
||||
|
||||
/**
|
||||
* This activity helps connect to the Wi-Fi network which is open or saved
|
||||
* This receiver helps connect to Wi-Fi network
|
||||
*/
|
||||
public class ConnectToWifiHandler extends Activity {
|
||||
public class ConnectToWifiHandler extends BroadcastReceiver {
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (context == null || intent == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Network network = getIntent().getParcelableExtra(ConnectivityManager.EXTRA_NETWORK);
|
||||
final Bundle accessPointState = getIntent().getBundleExtra(
|
||||
final Network network = intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK);
|
||||
final Bundle accessPointState = intent.getBundleExtra(
|
||||
WifiDialogActivity.KEY_ACCESS_POINT_STATE);
|
||||
|
||||
if (network != null) {
|
||||
WifiScanWorker.clearClickedWifi();
|
||||
final ConnectivityManager cm = getSystemService(ConnectivityManager.class);
|
||||
final ConnectivityManager cm = context.getSystemService(ConnectivityManager.class);
|
||||
// start captive portal app to sign in to network
|
||||
cm.startCaptivePortalApp(network);
|
||||
} else if (accessPointState != null) {
|
||||
connect(new AccessPoint(this, accessPointState));
|
||||
connect(context, new AccessPoint(context, accessPointState));
|
||||
}
|
||||
|
||||
finish();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void connect(AccessPoint accessPoint) {
|
||||
void connect(Context context, AccessPoint accessPoint) {
|
||||
ContextualWifiScanWorker.saveSession();
|
||||
WifiScanWorker.saveClickedWifi(accessPoint);
|
||||
|
||||
final WifiConnectListener connectListener = new WifiConnectListener(this);
|
||||
final WifiConnectListener connectListener = new WifiConnectListener(context);
|
||||
switch (WifiUtils.getConnectingType(accessPoint)) {
|
||||
case WifiUtils.CONNECT_TYPE_OSU_PROVISION:
|
||||
accessPoint.startOsuProvisioning(connectListener);
|
||||
@@ -68,7 +71,7 @@ public class ConnectToWifiHandler extends Activity {
|
||||
accessPoint.generateOpenNetworkConfig();
|
||||
|
||||
case WifiUtils.CONNECT_TYPE_SAVED_NETWORK:
|
||||
final WifiManager wifiManager = getSystemService(WifiManager.class);
|
||||
final WifiManager wifiManager = context.getSystemService(WifiManager.class);
|
||||
wifiManager.connect(accessPoint.getConfig(), connectListener);
|
||||
break;
|
||||
}
|
||||
|
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.settings.wifi.slice;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.os.SystemClock;
|
||||
|
||||
import com.android.settings.slices.SliceBackgroundWorker;
|
||||
|
||||
/**
|
||||
* {@link SliceBackgroundWorker} for Wi-Fi, used by {@link ContextualWifiSlice}.
|
||||
*/
|
||||
public class ContextualWifiScanWorker extends WifiScanWorker {
|
||||
|
||||
private static long sVisibleUiSessionToken;
|
||||
private static long sActiveSession;
|
||||
|
||||
public ContextualWifiScanWorker(Context context, Uri uri) {
|
||||
super(context, uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a new visible UI session for the purpose of automatically starting captive portal.
|
||||
*
|
||||
* A visible UI session is defined as a duration of time when a UI screen is visible to user.
|
||||
* Going to a sub-page and coming out breaks the continuation, leaving the page and coming back
|
||||
* breaks it too.
|
||||
*/
|
||||
public static void newVisibleUiSession() {
|
||||
sVisibleUiSessionToken = SystemClock.elapsedRealtime();
|
||||
}
|
||||
|
||||
static void saveSession() {
|
||||
sActiveSession = sVisibleUiSessionToken;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void clearClickedWifiOnSliceUnpinned() {
|
||||
// Do nothing for contextual Wi-Fi slice
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isSessionValid() {
|
||||
if (sVisibleUiSessionToken != sActiveSession) {
|
||||
clearClickedWifi();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -90,4 +90,9 @@ public class ContextualWifiSlice extends WifiSlice {
|
||||
&& !nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY)
|
||||
&& nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class getBackgroundWorkerClass() {
|
||||
return ContextualWifiScanWorker.class;
|
||||
}
|
||||
}
|
||||
|
@@ -50,7 +50,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* {@link SliceBackgroundWorker} for Wi-Fi, used by WifiSlice.
|
||||
* {@link SliceBackgroundWorker} for Wi-Fi, used by {@link WifiSlice}.
|
||||
*/
|
||||
public class WifiScanWorker extends SliceBackgroundWorker<AccessPoint> implements
|
||||
WifiTracker.WifiListener {
|
||||
@@ -84,7 +84,7 @@ public class WifiScanWorker extends SliceBackgroundWorker<AccessPoint> implement
|
||||
protected void onSliceUnpinned() {
|
||||
mWifiTracker.onStop();
|
||||
unregisterNetworkCallback();
|
||||
clearClickedWifi();
|
||||
clearClickedWifiOnSliceUnpinned();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -157,6 +157,14 @@ public class WifiScanWorker extends SliceBackgroundWorker<AccessPoint> implement
|
||||
return !TextUtils.isEmpty(ssid) && TextUtils.equals(ssid, sClickedWifiSsid);
|
||||
}
|
||||
|
||||
protected void clearClickedWifiOnSliceUnpinned() {
|
||||
clearClickedWifi();
|
||||
}
|
||||
|
||||
protected boolean isSessionValid() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void registerNetworkCallback(Network wifiNetwork) {
|
||||
if (wifiNetwork == null) {
|
||||
return;
|
||||
@@ -224,12 +232,13 @@ public class WifiScanWorker extends SliceBackgroundWorker<AccessPoint> implement
|
||||
|
||||
// Automatically start captive portal
|
||||
if (!prevIsCaptivePortal && mIsCaptivePortal
|
||||
&& isWifiClicked(mWifiTracker.getManager().getConnectionInfo())) {
|
||||
&& isWifiClicked(mWifiTracker.getManager().getConnectionInfo())
|
||||
&& isSessionValid()) {
|
||||
final Intent intent = new Intent(mContext, ConnectToWifiHandler.class)
|
||||
.putExtra(ConnectivityManager.EXTRA_NETWORK, network)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
// Starting activity in the system process needs to specify a user
|
||||
mContext.startActivityAsUser(intent, UserHandle.CURRENT);
|
||||
.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
|
||||
// Sending a broadcast in the system process needs to specify a user
|
||||
mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -94,6 +94,7 @@ public class WifiSlice implements CustomSliceable {
|
||||
final boolean isWifiEnabled = isWifiEnabled();
|
||||
ListBuilder listBuilder = getHeaderRow(isWifiEnabled);
|
||||
if (!isWifiEnabled) {
|
||||
WifiScanWorker.clearClickedWifi();
|
||||
return listBuilder.build();
|
||||
}
|
||||
|
||||
@@ -133,6 +134,17 @@ public class WifiSlice implements CustomSliceable {
|
||||
return listBuilder.build();
|
||||
}
|
||||
|
||||
private void handleNetworkCallback(WifiScanWorker worker, boolean isFirstApActive) {
|
||||
if (worker == null) {
|
||||
return;
|
||||
}
|
||||
if (isFirstApActive) {
|
||||
worker.registerNetworkCallback(mWifiManager.getCurrentNetwork());
|
||||
} else {
|
||||
worker.unregisterNetworkCallback();
|
||||
}
|
||||
}
|
||||
|
||||
private ListBuilder getHeaderRow(boolean isWifiEnabled) {
|
||||
final IconCompat icon = IconCompat.createWithResource(mContext,
|
||||
R.drawable.ic_settings_wireless);
|
||||
@@ -155,17 +167,6 @@ public class WifiSlice implements CustomSliceable {
|
||||
.setPrimaryAction(primarySliceAction));
|
||||
}
|
||||
|
||||
private void handleNetworkCallback(WifiScanWorker worker, boolean isFirstApActive) {
|
||||
if (worker == null) {
|
||||
return;
|
||||
}
|
||||
if (isFirstApActive) {
|
||||
worker.registerNetworkCallback(mWifiManager.getCurrentNetwork());
|
||||
} else {
|
||||
worker.unregisterNetworkCallback();
|
||||
}
|
||||
}
|
||||
|
||||
private ListBuilder.RowBuilder getAccessPointRow(AccessPoint accessPoint) {
|
||||
final boolean isCaptivePortal = accessPoint.isActive() && isCaptivePortal();
|
||||
final CharSequence title = accessPoint.getTitle();
|
||||
@@ -175,9 +176,8 @@ public class WifiSlice implements CustomSliceable {
|
||||
.setTitleItem(levelIcon, ListBuilder.ICON_IMAGE)
|
||||
.setTitle(title)
|
||||
.setSubtitle(summary)
|
||||
.setPrimaryAction(SliceAction.createDeeplink(
|
||||
getAccessPointAction(accessPoint, isCaptivePortal), levelIcon,
|
||||
ListBuilder.ICON_IMAGE, title));
|
||||
.setPrimaryAction(getAccessPointAction(accessPoint, isCaptivePortal, levelIcon,
|
||||
title));
|
||||
|
||||
if (isCaptivePortal) {
|
||||
rowBuilder.addEndItem(getCaptivePortalEndAction(accessPoint, title));
|
||||
@@ -203,7 +203,7 @@ public class WifiSlice implements CustomSliceable {
|
||||
final Drawable d = mContext.getDrawable(
|
||||
com.android.settingslib.Utils.getWifiIconResource(accessPoint.getLevel()));
|
||||
|
||||
@ColorInt int color;
|
||||
final @ColorInt int color;
|
||||
if (accessPoint.isActive()) {
|
||||
final NetworkInfo.State state = accessPoint.getNetworkInfo().getState();
|
||||
if (state == NetworkInfo.State.CONNECTED) {
|
||||
@@ -232,36 +232,54 @@ public class WifiSlice implements CustomSliceable {
|
||||
}
|
||||
|
||||
private SliceAction getCaptivePortalEndAction(AccessPoint accessPoint, CharSequence title) {
|
||||
return SliceAction.createDeeplink(
|
||||
getAccessPointAction(accessPoint, false /* isCaptivePortal */),
|
||||
IconCompat.createWithResource(mContext, R.drawable.ic_settings_accent),
|
||||
ListBuilder.ICON_IMAGE, title);
|
||||
return getAccessPointAction(accessPoint, false /* isCaptivePortal */,
|
||||
IconCompat.createWithResource(mContext, R.drawable.ic_settings_accent), title);
|
||||
}
|
||||
|
||||
private PendingIntent getAccessPointAction(AccessPoint accessPoint, boolean isCaptivePortal) {
|
||||
private SliceAction getAccessPointAction(AccessPoint accessPoint, boolean isCaptivePortal,
|
||||
IconCompat icon, CharSequence title) {
|
||||
final int requestCode = accessPoint.hashCode();
|
||||
if (isCaptivePortal) {
|
||||
final Intent intent = new Intent(mContext, ConnectToWifiHandler.class)
|
||||
.putExtra(ConnectivityManager.EXTRA_NETWORK, mWifiManager.getCurrentNetwork());
|
||||
return getBroadcastAction(requestCode, intent, icon, title);
|
||||
}
|
||||
|
||||
final Bundle extras = new Bundle();
|
||||
accessPoint.saveWifiState(extras);
|
||||
|
||||
Intent intent;
|
||||
if (isCaptivePortal) {
|
||||
intent = new Intent(mContext, ConnectToWifiHandler.class);
|
||||
intent.putExtra(ConnectivityManager.EXTRA_NETWORK, mWifiManager.getCurrentNetwork());
|
||||
} else if (accessPoint.isActive()) {
|
||||
intent = new SubSettingLauncher(mContext)
|
||||
if (accessPoint.isActive()) {
|
||||
final Intent intent = new SubSettingLauncher(mContext)
|
||||
.setTitleRes(R.string.pref_title_network_details)
|
||||
.setDestination(WifiNetworkDetailsFragment.class.getName())
|
||||
.setArguments(extras)
|
||||
.setSourceMetricsCategory(SettingsEnums.WIFI)
|
||||
.toIntent();
|
||||
return getActivityAction(requestCode, intent, icon, title);
|
||||
} else if (WifiUtils.getConnectingType(accessPoint) != WifiUtils.CONNECT_TYPE_OTHERS) {
|
||||
intent = new Intent(mContext, ConnectToWifiHandler.class);
|
||||
intent.putExtra(WifiDialogActivity.KEY_ACCESS_POINT_STATE, extras);
|
||||
final Intent intent = new Intent(mContext, ConnectToWifiHandler.class)
|
||||
.putExtra(WifiDialogActivity.KEY_ACCESS_POINT_STATE, extras);
|
||||
return getBroadcastAction(requestCode, intent, icon, title);
|
||||
} else {
|
||||
intent = new Intent(mContext, WifiDialogActivity.class);
|
||||
intent.putExtra(WifiDialogActivity.KEY_ACCESS_POINT_STATE, extras);
|
||||
final Intent intent = new Intent(mContext, WifiDialogActivity.class)
|
||||
.putExtra(WifiDialogActivity.KEY_ACCESS_POINT_STATE, extras);
|
||||
return getActivityAction(requestCode, intent, icon, title);
|
||||
}
|
||||
return PendingIntent.getActivity(mContext, accessPoint.hashCode() /* requestCode */,
|
||||
intent, 0 /* flags */);
|
||||
}
|
||||
|
||||
private SliceAction getActivityAction(int requestCode, Intent intent, IconCompat icon,
|
||||
CharSequence title) {
|
||||
final PendingIntent pi = PendingIntent.getActivity(mContext, requestCode, intent,
|
||||
0 /* flags */);
|
||||
return SliceAction.createDeeplink(pi, icon, ListBuilder.ICON_IMAGE, title);
|
||||
}
|
||||
|
||||
private SliceAction getBroadcastAction(int requestCode, Intent intent, IconCompat icon,
|
||||
CharSequence title) {
|
||||
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
|
||||
final PendingIntent pi = PendingIntent.getBroadcast(mContext, requestCode, intent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
return SliceAction.create(pi, icon, ListBuilder.ICON_IMAGE, title);
|
||||
}
|
||||
|
||||
private ListBuilder.RowBuilder getLoadingRow(CharSequence placeholder) {
|
||||
@@ -277,7 +295,7 @@ public class WifiSlice implements CustomSliceable {
|
||||
.setSubtitle(title);
|
||||
}
|
||||
|
||||
protected boolean isCaptivePortal() {
|
||||
private boolean isCaptivePortal() {
|
||||
final NetworkCapabilities nc = mConnectivityManager.getNetworkCapabilities(
|
||||
mWifiManager.getCurrentNetwork());
|
||||
return WifiUtils.canSignIntoNetwork(nc);
|
||||
|
Reference in New Issue
Block a user