diff options
author | 2024-01-10 07:30:08 +0000 | |
---|---|---|
committer | 2024-01-10 07:30:08 +0000 | |
commit | 782c1fd11e2e80de97992e65ab9c65ebf0e4a1ba (patch) | |
tree | 13c26de54446a2612611a891cc68442d2341d3a0 | |
parent | 4c2e9d3ce026822fbdc7bac25572a800f4f51f4d (diff) | |
parent | 7575405faabc058f4093ff1659efa5d04a8def91 (diff) |
Merge changes from topic "VPN_ICON" into main
* changes:
Adjust the NetworkRequest configuration used by SecurityController
Design of the VPN icon reflects the invalidated status
Update the VPN icon to reflect the validation status of the VPN network
8 files changed, 220 insertions, 5 deletions
diff --git a/packages/SystemUI/res/drawable/stat_sys_no_internet_branded_vpn.xml b/packages/SystemUI/res/drawable/stat_sys_no_internet_branded_vpn.xml new file mode 100644 index 000000000000..2161a62ada9c --- /dev/null +++ b/packages/SystemUI/res/drawable/stat_sys_no_internet_branded_vpn.xml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +** +** Copyright 2023, 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. +*/ +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="17dp" + android:height="17dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M12.09,9C11.11,7.5 9.43,6.5 7.5,6.5C4.46,6.5 2,8.96 2,12c0,3.04 2.46,5.5 5.5,5.5c1.93,0 3.61,-1 4.59,-2.5H14v3h4V9H12.09zM18,13hv3h-2v-3h-5.16c-0.43,1.44 -1.76,2.5 -3.34,2.5C5.57,15.5 4,13.93 4,12c0,-1.93 1.57,-3.5 3.5,-3.5c1.58,0 2.9,1.06 3.34,2.5H18V13z"/> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M7.5,12m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"/> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M22,10h-2v8h2V10z"/> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M22,20h-2v2h2V20z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/stat_sys_no_internet_vpn_ic.xml b/packages/SystemUI/res/drawable/stat_sys_no_internet_vpn_ic.xml new file mode 100644 index 000000000000..2161a62ada9c --- /dev/null +++ b/packages/SystemUI/res/drawable/stat_sys_no_internet_vpn_ic.xml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +** +** Copyright 2023, 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. +*/ +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="17dp" + android:height="17dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M12.09,9C11.11,7.5 9.43,6.5 7.5,6.5C4.46,6.5 2,8.96 2,12c0,3.04 2.46,5.5 5.5,5.5c1.93,0 3.61,-1 4.59,-2.5H14v3h4V9H12.09zM18,13hv3h-2v-3h-5.16c-0.43,1.44 -1.76,2.5 -3.34,2.5C5.57,15.5 4,13.93 4,12c0,-1.93 1.57,-3.5 3.5,-3.5c1.58,0 2.9,1.06 3.34,2.5H18V13z"/> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M7.5,12m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"/> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M22,10h-2v8h2V10z"/> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M22,20h-2v2h2V20z"/> +</vector> diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java index 344e56cf570f..ae7c170fe8c6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java @@ -118,15 +118,25 @@ public class StatusBarSignalPolicy implements SignalCallback, private void updateVpn() { boolean vpnVisible = mSecurityController.isVpnEnabled(); - int vpnIconId = currentVpnIconId(mSecurityController.isVpnBranded()); + int vpnIconId = currentVpnIconId( + mSecurityController.isVpnBranded(), + mSecurityController.isVpnValidated()); mIconController.setIcon(mSlotVpn, vpnIconId, mContext.getResources().getString(R.string.accessibility_vpn_on)); mIconController.setIconVisibility(mSlotVpn, vpnVisible); } - private int currentVpnIconId(boolean isBranded) { - return isBranded ? R.drawable.stat_sys_branded_vpn : R.drawable.stat_sys_vpn_ic; + private int currentVpnIconId(boolean isBranded, boolean isValidated) { + if (isBranded) { + return isValidated + ? R.drawable.stat_sys_branded_vpn + : R.drawable.stat_sys_no_internet_branded_vpn; + } else { + return isValidated + ? R.drawable.stat_sys_vpn_ic + : R.drawable.stat_sys_no_internet_vpn_ic; + } } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java index 3be14bc867a1..10bf0680b567 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java @@ -48,6 +48,8 @@ public interface SecurityController extends CallbackController<SecurityControlle boolean isNetworkLoggingEnabled(); boolean isVpnEnabled(); boolean isVpnRestricted(); + /** Whether the VPN network is validated. */ + boolean isVpnValidated(); /** Whether the VPN app should use branded VPN iconography. */ boolean isVpnBranded(); String getPrimaryVpnName(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java index 03656f000c07..ada219635efb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java @@ -15,6 +15,9 @@ */ package com.android.systemui.statusbar.policy; +import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; +import static android.net.NetworkCapabilities.TRANSPORT_VPN; + import android.annotation.Nullable; import android.app.admin.DeviceAdminInfo; import android.app.admin.DevicePolicyManager; @@ -32,7 +35,9 @@ import android.content.pm.UserInfo; import android.graphics.drawable.Drawable; import android.net.ConnectivityManager; import android.net.ConnectivityManager.NetworkCallback; +import android.net.LinkProperties; import android.net.Network; +import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.net.VpnManager; import android.os.Handler; @@ -76,7 +81,10 @@ public class SecurityControllerImpl implements SecurityController { private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private static final NetworkRequest REQUEST = - new NetworkRequest.Builder().clearCapabilities().build(); + new NetworkRequest.Builder() + .clearCapabilities() + .addTransportType(TRANSPORT_VPN) + .build(); private static final int NO_NETWORK = -1; private static final String VPN_BRANDED_META_DATA = "com.android.systemui.IS_BRANDED"; @@ -99,6 +107,8 @@ public class SecurityControllerImpl implements SecurityController { private SparseArray<VpnConfig> mCurrentVpns = new SparseArray<>(); private int mCurrentUserId; private int mVpnUserId; + @GuardedBy("mNetworkProperties") + private final SparseArray<NetworkProperties> mNetworkProperties = new SparseArray<>(); // Key: userId, Value: whether the user has CACerts installed // Needs to be cached here since the query has to be asynchronous @@ -162,6 +172,21 @@ public class SecurityControllerImpl implements SecurityController { pw.print(mCurrentVpns.valueAt(i).user); } pw.println("}"); + pw.print(" mNetworkProperties={"); + synchronized (mNetworkProperties) { + for (int i = 0; i < mNetworkProperties.size(); ++i) { + if (i > 0) { + pw.print(", "); + } + pw.print(mNetworkProperties.keyAt(i)); + pw.print("={"); + pw.print(mNetworkProperties.valueAt(i).interfaceName); + pw.print(", "); + pw.print(mNetworkProperties.valueAt(i).validated); + pw.print("}"); + } + } + pw.println("}"); } @Override @@ -304,6 +329,26 @@ public class SecurityControllerImpl implements SecurityController { } @Override + public boolean isVpnValidated() { + // Prioritize reporting the network status of the parent user. + final VpnConfig primaryVpnConfig = mCurrentVpns.get(mVpnUserId); + if (primaryVpnConfig != null) { + return getVpnValidationStatus(primaryVpnConfig); + } + // Identify any Unvalidated status in each active VPN network within other profiles. + for (int profileId : mUserManager.getEnabledProfileIds(mVpnUserId)) { + final VpnConfig vpnConfig = mCurrentVpns.get(profileId); + if (vpnConfig == null) { + continue; + } + if (!getVpnValidationStatus(vpnConfig)) { + return false; + } + } + return true; + } + + @Override public boolean hasCACertInCurrentUser() { Boolean hasCACerts = mHasCACerts.get(mCurrentUserId); return hasCACerts != null && hasCACerts.booleanValue(); @@ -491,11 +536,74 @@ public class SecurityControllerImpl implements SecurityController { @Override public void onLost(Network network) { if (DEBUG) Log.d(TAG, "onLost " + network.getNetId()); + synchronized (mNetworkProperties) { + mNetworkProperties.delete(network.getNetId()); + } updateState(); fireCallbacks(); }; + + + @Override + public void onCapabilitiesChanged(Network network, NetworkCapabilities nc) { + if (DEBUG) Log.d(TAG, "onCapabilitiesChanged " + network.getNetId()); + final NetworkProperties properties; + synchronized (mNetworkProperties) { + properties = mNetworkProperties.get(network.getNetId()); + } + // When a new network appears, the system first notifies the application about + // its capabilities through onCapabilitiesChanged. This initial notification + // will be skipped because the interface information is included in the + // subsequent onLinkPropertiesChanged call. After validating the network, the + // system might send another onCapabilitiesChanged notification if the network + // becomes validated. + if (properties == null) { + return; + } + final boolean validated = nc.hasCapability(NET_CAPABILITY_VALIDATED); + if (properties.validated != validated) { + properties.validated = validated; + fireCallbacks(); + } + } + + @Override + public void onLinkPropertiesChanged(Network network, LinkProperties linkProperties) { + if (DEBUG) Log.d(TAG, "onLinkPropertiesChanged " + network.getNetId()); + final String interfaceName = linkProperties.getInterfaceName(); + if (interfaceName == null) { + Log.w(TAG, "onLinkPropertiesChanged event with null interface"); + return; + } + synchronized (mNetworkProperties) { + final NetworkProperties properties = mNetworkProperties.get(network.getNetId()); + if (properties == null) { + mNetworkProperties.put( + network.getNetId(), + new NetworkProperties(interfaceName, false)); + } else { + properties.interfaceName = interfaceName; + } + } + } }; + /** + * Retrieve the validation status of the VPN network associated with the given VpnConfig. + */ + private boolean getVpnValidationStatus(@NonNull VpnConfig vpnConfig) { + synchronized (mNetworkProperties) { + // Find the network has the same interface as the VpnConfig + for (int i = 0; i < mNetworkProperties.size(); ++i) { + if (mNetworkProperties.valueAt(i).interfaceName.equals(vpnConfig.interfaze)) { + return mNetworkProperties.valueAt(i).validated; + } + } + } + // If no matching network is found, consider it validated. + return true; + } + private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (KeyChain.ACTION_TRUST_STORE_CHANGED.equals(intent.getAction())) { @@ -506,4 +614,17 @@ public class SecurityControllerImpl implements SecurityController { } } }; + + /** + * A data class to hold specific Network properties received through the NetworkCallback. + */ + private static class NetworkProperties { + public String interfaceName; + public boolean validated; + + NetworkProperties(@NonNull String interfaceName, boolean validated) { + this.interfaceName = interfaceName; + this.validated = validated; + } + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java index c35bc69bf15b..bcc9272b45f8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.policy; import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_FINANCED; +import static android.net.NetworkCapabilities.TRANSPORT_VPN; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -213,7 +214,8 @@ public class SecurityControllerTest extends SysuiTestCase { public void testNetworkRequest() { verify(mConnectivityManager, times(1)).registerNetworkCallback(argThat( (NetworkRequest request) -> - request.equals(new NetworkRequest.Builder().clearCapabilities().build()) + request.equals(new NetworkRequest.Builder() + .clearCapabilities().addTransportType(TRANSPORT_VPN).build()) ), any(NetworkCallback.class)); } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeSecurityController.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeSecurityController.kt index 021e7dff9120..ac90a45450d0 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeSecurityController.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeSecurityController.kt @@ -77,6 +77,8 @@ class FakeSecurityController( override fun isVpnBranded(): Boolean = fakeState.isVpnBranded + override fun isVpnValidated(): Boolean = fakeState.isVpnValidated + override fun getPrimaryVpnName(): String? = fakeState.primaryVpnName override fun getWorkProfileVpnName(): String? = fakeState.workProfileVpnName @@ -110,6 +112,7 @@ class FakeSecurityController( var isVpnEnabled: Boolean = false, var isVpnRestricted: Boolean = false, var isVpnBranded: Boolean = false, + var isVpnValidated: Boolean = false, var primaryVpnName: String? = null, var workProfileVpnName: String? = null, var hasCACertInCurrentUser: Boolean = false, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeSecurityController.java b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeSecurityController.java index 76199e3168da..791165d97795 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeSecurityController.java +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeSecurityController.java @@ -109,6 +109,11 @@ public class FakeSecurityController extends BaseLeakChecker<SecurityControllerCa } @Override + public boolean isVpnValidated() { + return false; + } + + @Override public String getPrimaryVpnName() { return null; } |