diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2021-07-15 01:28:40 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2021-07-15 01:28:40 +0000 |
commit | e056d40da0162b2805c5df079602fbf2da308bbb (patch) | |
tree | 14b46d718269544cf078dc96801f5a0f72e6dafb | |
parent | e5a2aa76cbd0249ecec3818af74033bebdb0b1ad (diff) | |
parent | e23d9b33c8c06ffd1cb464f040736d292c297134 (diff) | |
download | sl4a-android12-mainline-conscrypt-release.tar.gz |
Snap for 7550844 from e23d9b33c8c06ffd1cb464f040736d292c297134 to mainline-conscrypt-releaseandroid-mainline-12.0.0_r8android-mainline-12.0.0_r25android12-mainline-conscrypt-release
Change-Id: Ie838d4d9910073cd54db950c148253f8ea35be67
35 files changed, 1417 insertions, 401 deletions
diff --git a/Android.bp b/Android.bp new file mode 100644 index 00000000..85630370 --- /dev/null +++ b/Android.bp @@ -0,0 +1,44 @@ +// +// Copyright (C) 2021 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 { + default_applicable_licenses: ["external_sl4a_license"], +} + +// Added automatically by a large-scale-change that took the approach of +// 'apply every license found to every target'. While this makes sure we respect +// every license restriction, it may not be entirely correct. +// +// e.g. GPL in an MIT project might only apply to the contrib/ directory. +// +// Please consider splitting the single license below into multiple licenses, +// taking care not to lose any license_kind information, and overriding the +// default license using the 'licenses: [...]' property on targets as needed. +// +// For unused files, consider creating a 'fileGroup' with "//visibility:private" +// to attach the license to, and including a comment whether the files may be +// used in the current project. +// See: http://go/android-license-faq +license { + name: "external_sl4a_license", + visibility: [":__subpackages__"], + license_kinds: [ + "SPDX-license-identifier-Apache-2.0", + "SPDX-license-identifier-GPL-2.0", + ], + license_text: [ + "NOTICE", + ], +} diff --git a/Common/Android.bp b/Common/Android.bp index 6578c143..ad42d294 100644 --- a/Common/Android.bp +++ b/Common/Android.bp @@ -14,6 +14,15 @@ // limitations under the License. // +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "external_sl4a_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["external_sl4a_license"], +} + java_library { name: "sl4a.Common", owner: "google", @@ -23,19 +32,25 @@ java_library { "android-common", "sl4a.Utils", "junit", + "modules-utils-build", ], sdk_version: "core_platform", libs: [ "framework-wifi.impl", // allow SL4A to access @hide Wifi APIs + "framework-connectivity.impl", "framework", "telephony-common", "ims-common", + "bouncycastle-repackaged-unbundled", ], srcs: [ "src/com/googlecode/android_scripting/**/*.java", "src/org/apache/commons/codec/**/*.java", + ":cellbroadcast-shared-with-sl4a", + ":cellbroadcast-util-shared-srcs", + ":cellbroadcast-constants-shared-srcs", ], } diff --git a/Common/src/com/googlecode/android_scripting/facade/AndroidFacade.java b/Common/src/com/googlecode/android_scripting/facade/AndroidFacade.java index 87b50cdd..1689c88a 100644 --- a/Common/src/com/googlecode/android_scripting/facade/AndroidFacade.java +++ b/Common/src/com/googlecode/android_scripting/facade/AndroidFacade.java @@ -44,6 +44,8 @@ import android.text.method.PasswordTransformationMethod; import android.widget.EditText; import android.widget.Toast; +import com.android.modules.utils.build.SdkLevel; + import com.googlecode.android_scripting.BaseApplication; import com.googlecode.android_scripting.FileUtils; import com.googlecode.android_scripting.FutureActivityTaskExecutor; @@ -600,6 +602,16 @@ public class AndroidFacade extends RpcReceiver { return Build.VERSION.SDK_INT; } + @Rpc(description = "Returns whether the device is running SDK at least R") + public boolean isSdkAtLeastR() { + return SdkLevel.isAtLeastR(); + } + + @Rpc(description = "Returns whether the device is running SDK at least S") + public boolean isSdkAtLeastS() { + return SdkLevel.isAtLeastS(); + } + @Rpc(description = "Returns the current device time.") public Long getBuildTime() { return Build.TIME; @@ -857,7 +869,8 @@ public class AndroidFacade extends RpcReceiver { @RpcParameter(name = "message") String message) { createNotificationChannel(); // This contentIntent is a noop. - PendingIntent contentIntent = PendingIntent.getService(mService, 0, new Intent(), 0); + PendingIntent contentIntent = PendingIntent.getService(mService, 0, new Intent(), + PendingIntent.FLAG_IMMUTABLE); Notification.Builder builder = new Notification.Builder(mService, CHANNEL_ID); builder.setSmallIcon(mResources.getLogo48()) .setTicker(message) diff --git a/Common/src/com/googlecode/android_scripting/facade/CertInstallerHelper.java b/Common/src/com/googlecode/android_scripting/facade/CertInstallerHelper.java index e4c36c13..d3d69c0f 100644 --- a/Common/src/com/googlecode/android_scripting/facade/CertInstallerHelper.java +++ b/Common/src/com/googlecode/android_scripting/facade/CertInstallerHelper.java @@ -17,33 +17,31 @@ package com.googlecode.android_scripting.facade; import android.os.Environment; -import android.security.Credentials; -import android.security.KeyStore; import android.util.Log; import com.android.internal.net.VpnProfile; -import com.android.org.bouncycastle.asn1.ASN1InputStream; -import com.android.org.bouncycastle.asn1.ASN1Sequence; -import com.android.org.bouncycastle.asn1.DEROctetString; -import com.android.org.bouncycastle.asn1.x509.BasicConstraints; - -import junit.framework.Assert; +import com.android.internal.org.bouncycastle.asn1.ASN1InputStream; +import com.android.internal.org.bouncycastle.asn1.ASN1Sequence; +import com.android.internal.org.bouncycastle.asn1.DEROctetString; +import com.android.internal.org.bouncycastle.asn1.x509.BasicConstraints; import libcore.io.Streams; +import junit.framework.Assert; + import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; +import java.security.KeyStore; import java.security.KeyStore.PasswordProtection; import java.security.KeyStore.PrivateKeyEntry; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.UnrecoverableEntryException; import java.security.cert.Certificate; -import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.ArrayList; @@ -58,21 +56,27 @@ import java.util.List; public class CertInstallerHelper { private static final String TAG = "CertInstallerHelper"; /* Define a password to unlock keystore after it is reset */ - private static final String CERT_STORE_PASSWORD = "password"; - private final int mUid = KeyStore.UID_SELF; private PrivateKey mUserKey; // private key private X509Certificate mUserCert; // user certificate private List<X509Certificate> mCaCerts = new ArrayList<X509Certificate>(); - private KeyStore mKeyStore = KeyStore.getInstance(); + private final KeyStore mKeyStore; /** - * Unlock keystore and set password + * Delete all key for caller. */ public CertInstallerHelper() { - for (String key : mKeyStore.list("")) { - mKeyStore.delete(key, KeyStore.UID_SELF); + try { + mKeyStore = KeyStore.getInstance("AndroidKeyStore"); + mKeyStore.load(null); + final Enumeration<String> aliases = mKeyStore.aliases(); + while (aliases.hasMoreElements()) { + mKeyStore.deleteEntry(aliases.nextElement()); + } + } catch (KeyStoreException | CertificateException | NoSuchAlgorithmException + | IOException e) { + Log.e(TAG, "Failed to open and cleanup Keystore.", e); + throw new RuntimeException("Failed to open and cleanup Keystore.", e); } - mKeyStore.onUserPasswordChanged(CERT_STORE_PASSWORD); } private void extractCertificate(String certFile, String password) { @@ -166,7 +170,7 @@ public class CertInstallerHelper { /** * Extract certificate from the given file, and install it to keystore - * @param name certificate name + * @param profile VpnProfile * @param certFile .p12 file which includes certificates * @param password password to extract the .p12 file */ @@ -174,51 +178,39 @@ public class CertInstallerHelper { // extract private keys, certificates from the provided file extractCertificate(certFile, password); // install certificate to the keystore - int flags = KeyStore.FLAG_ENCRYPTED; try { + boolean caInstalledWithUserKey = false; + if (mUserKey != null) { Log.v(TAG, "has private key"); - String key = Credentials.USER_PRIVATE_KEY + profile.ipsecUserCert; - byte[] value = mUserKey.getEncoded(); - - if (!mKeyStore.importKey(key, value, mUid, flags)) { - Log.e(TAG, "Failed to install " + key + " as user " + mUid); - return; + if (mUserCert == null) { + throw new AssertionError("Must have user cert if user key is installed."); } - Log.v(TAG, "install " + key + " as user " + mUid + " is successful"); - } - - if (mUserCert != null) { - String certName = Credentials.USER_CERTIFICATE + profile.ipsecUserCert; - byte[] certData = Credentials.convertToPem(mUserCert); - - if (!mKeyStore.put(certName, certData, mUid, flags)) { - Log.e(TAG, "Failed to install " + certName + " as user " + mUid); - return; + final List<Certificate> certChain = new ArrayList<Certificate>(); + certChain.add(mUserCert); + if (profile.ipsecUserCert.equals(profile.ipsecCaCert)) { + // If the CA certs should be installed under the same alias they have to be + // added to the end of the certificate chain. + certChain.addAll(mCaCerts); + // Make a note that we have installed the CA cert chain along with the + // user key and cert. + caInstalledWithUserKey = true; } - Log.v(TAG, "install " + certName + " as user" + mUid + " is successful."); + mKeyStore.setKeyEntry(profile.ipsecUserCert, mUserKey, null, + certChain.toArray(new Certificate[0])); + Log.v(TAG, "install " + profile.ipsecUserCert + " is successful"); } - if (!mCaCerts.isEmpty()) { - String caListName = Credentials.CA_CERTIFICATE + profile.ipsecCaCert; - X509Certificate[] caCerts = mCaCerts.toArray(new X509Certificate[mCaCerts.size()]); - byte[] caListData = Credentials.convertToPem(caCerts); - - if (!mKeyStore.put(caListName, caListData, mUid, flags)) { - Log.e(TAG, "Failed to install " + caListName + " as user " + mUid); - return; + if (!(mCaCerts.isEmpty() || caInstalledWithUserKey)) { + if (mCaCerts.size() != 1) { + throw new AssertionError("Trusted certificate cannot be a cert chain."); } - Log.v(TAG, " install " + caListName + " as user " + mUid + " is successful"); + mKeyStore.setCertificateEntry(profile.ipsecCaCert, mCaCerts.get(0)); + Log.v(TAG, " install " + profile.ipsecCaCert + " is successful"); } - } catch (CertificateEncodingException e) { - Log.e(TAG, "Exception while convert certificates to pem " + e); + } catch (KeyStoreException e) { + Log.e(TAG, "Exception trying to import certificates. " + e); throw new AssertionError(e); - } catch (IOException e) { - Log.e(TAG, "IOException while convert to pem: " + e); } } - - public int getUid() { - return mUid; - } } diff --git a/Common/src/com/googlecode/android_scripting/facade/ConnectivityConstants.java b/Common/src/com/googlecode/android_scripting/facade/ConnectivityConstants.java index 8e5297ba..867f6245 100644 --- a/Common/src/com/googlecode/android_scripting/facade/ConnectivityConstants.java +++ b/Common/src/com/googlecode/android_scripting/facade/ConnectivityConstants.java @@ -66,6 +66,7 @@ public class ConnectivityConstants { public static final String NETWORK_CALLBACK_EVENT = "networkCallbackEvent"; public static final String MAX_MS_TO_LIVE = "maxMsToLive"; public static final String RSSI = "rssi"; + public static final String METERED = "metered"; public static final String INTERFACE_NAME = "interfaceName"; public static final String CREATE_TIMESTAMP = "creation_timestamp"; public static final String CURRENT_TIMESTAMP = "current_timestamp"; @@ -78,9 +79,20 @@ public class ConnectivityConstants { public static final String TetheringFailedCallback = "ConnectivityManagerOnTetheringFailed"; /** + * Constants for Meteredness + */ + public static final Integer NET_CAPABILITY_TEMPORARILY_NOT_METERED = 25; + + /** * Constants for PrivateDnsMode */ public static final String PrivateDnsModeOff = "off"; public static final String PrivateDnsModeOpportunistic = "opportunistic"; public static final String PrivateDnsModeStrict = "hostname"; + + /** + * Constants for NetworkCapabilties/NetworkRequest + */ + public static final String NET_CAPABILITIES_TRANSPORT_TYPE = "TransportType"; + public static final String NET_CAPABILITIES_CAPABILITIES = "Capability"; } diff --git a/Common/src/com/googlecode/android_scripting/facade/ConnectivityEvents.java b/Common/src/com/googlecode/android_scripting/facade/ConnectivityEvents.java index 5c12b7c1..64c6e650 100644 --- a/Common/src/com/googlecode/android_scripting/facade/ConnectivityEvents.java +++ b/Common/src/com/googlecode/android_scripting/facade/ConnectivityEvents.java @@ -17,8 +17,8 @@ package com.googlecode.android_scripting.facade; import android.net.NetworkCapabilities; -import android.net.wifi.aware.WifiAwareNetworkInfo; +import com.googlecode.android_scripting.jsonrpc.JsonBuilder; import com.googlecode.android_scripting.jsonrpc.JsonSerializable; import org.json.JSONException; @@ -136,29 +136,7 @@ public class ConnectivityEvents { */ public JSONObject toJSON() throws JSONException { JSONObject json = super.toJSON(); - json.put(ConnectivityConstants.NetworkCallbackContainer.RSSI, - mNetworkCapabilities.getSignalStrength()); - if (mNetworkCapabilities.getNetworkSpecifier() != null) { - json.put("network_specifier", - mNetworkCapabilities.getNetworkSpecifier().toString()); - } - if (mNetworkCapabilities.getTransportInfo() instanceof WifiAwareNetworkInfo) { - WifiAwareNetworkInfo anc = - (WifiAwareNetworkInfo) mNetworkCapabilities.getTransportInfo(); - - String ipv6 = anc.getPeerIpv6Addr().toString(); - if (ipv6.charAt(0) == '/') { - ipv6 = ipv6.substring(1); - } - json.put("aware_ipv6", ipv6); - if (anc.getPort() != 0) { - json.put("aware_port", anc.getPort()); - } - if (anc.getTransportProtocol() != -1) { - json.put("aware_transport_protocol", anc.getTransportProtocol()); - } - } - return json; + return JsonBuilder.buildNetworkCapabilities(json, mNetworkCapabilities); } } diff --git a/Common/src/com/googlecode/android_scripting/facade/ConnectivityManagerFacade.java b/Common/src/com/googlecode/android_scripting/facade/ConnectivityManagerFacade.java index fb66b264..26f00128 100644 --- a/Common/src/com/googlecode/android_scripting/facade/ConnectivityManagerFacade.java +++ b/Common/src/com/googlecode/android_scripting/facade/ConnectivityManagerFacade.java @@ -16,6 +16,8 @@ package com.googlecode.android_scripting.facade; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; + import android.app.Service; import android.app.usage.NetworkStats; import android.app.usage.NetworkStats.Bucket; @@ -32,18 +34,22 @@ import android.net.NetworkInfo; import android.net.NetworkPolicy; import android.net.NetworkPolicyManager; import android.net.NetworkRequest; +import android.net.NetworkSpecifier; import android.net.ProxyInfo; import android.net.RouteInfo; -import android.net.StringNetworkSpecifier; import android.net.Uri; +import android.net.wifi.WifiNetworkSpecifier; import android.os.Bundle; import android.os.RemoteException; import android.provider.Settings; +import com.android.modules.utils.build.SdkLevel; + import com.google.common.io.ByteStreams; import com.googlecode.android_scripting.FileUtils; import com.googlecode.android_scripting.Log; import com.googlecode.android_scripting.facade.wifi.WifiAwareManagerFacade; +import com.googlecode.android_scripting.facade.wifi.WifiManagerFacade; import com.googlecode.android_scripting.jsonrpc.RpcReceiver; import com.googlecode.android_scripting.rpc.Rpc; import com.googlecode.android_scripting.rpc.RpcOptional; @@ -66,6 +72,7 @@ import java.net.NetworkInterface; import java.net.SocketException; import java.net.URL; import java.net.URLConnection; +import java.security.GeneralSecurityException; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; @@ -122,7 +129,19 @@ public class ConnectivityManagerFacade extends RpcReceiver { } } - class NetworkCallback extends ConnectivityManager.NetworkCallback { + /** + * Used to dispatch to a different constructor depending on R or S, since + * {@link ConnectivityManager.NetworkCallback#NetworkCallback(int)} was added in S. + */ + private NetworkCallback newNetworkCallback(int events) { + if (SdkLevel.isAtLeastS()) { + return new NetworkCallback(events); + } else { + return new NetworkCallback(events, false); + } + } + + private class NetworkCallback extends ConnectivityManager.NetworkCallback { public static final int EVENT_INVALID = -1; public static final int EVENT_NONE = 0; public static final int EVENT_PRECHECK = 1 << 0; @@ -135,23 +154,39 @@ public class ConnectivityManagerFacade extends RpcReceiver { public static final int EVENT_RESUMED = 1 << 7; public static final int EVENT_LINK_PROPERTIES_CHANGED = 1 << 8; public static final int EVENT_BLOCKED_STATUS_CHANGED = 1 << 9; - public static final int EVENT_ALL = EVENT_PRECHECK | - EVENT_AVAILABLE | - EVENT_LOSING | - EVENT_LOST | - EVENT_UNAVAILABLE | - EVENT_CAPABILITIES_CHANGED | - EVENT_SUSPENDED | - EVENT_RESUMED | - EVENT_LINK_PROPERTIES_CHANGED - | EVENT_BLOCKED_STATUS_CHANGED; + public static final int EVENT_ALL = + EVENT_PRECHECK + | EVENT_AVAILABLE + | EVENT_LOSING + | EVENT_LOST + | EVENT_UNAVAILABLE + | EVENT_CAPABILITIES_CHANGED + | EVENT_SUSPENDED + | EVENT_RESUMED + | EVENT_LINK_PROPERTIES_CHANGED + | EVENT_BLOCKED_STATUS_CHANGED; private int mEvents; public String mId; private long mCreateTimestamp; - public NetworkCallback(int events) { + /** Called in >= Android S where super(int) does exist. */ + private NetworkCallback(int events) { + super(ConnectivityManager.NetworkCallback.FLAG_INCLUDE_LOCATION_INFO); + init(events); + } + + /** + * Called in <= Android R where super(int) doesn't exist. + * @param ignore placeholder argument to differentiate between R and S constructors' method + * signatures. + */ + private NetworkCallback(int events, boolean ignore) { super(); + init(events); + } + + private void init(int events) { mEvents = events; mId = this.toString(); mCreateTimestamp = System.currentTimeMillis(); @@ -431,7 +466,7 @@ public class ConnectivityManagerFacade extends RpcReceiver { builder.setSignalStrength((int) rssi); builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI); NetworkRequest networkRequest = builder.build(); - mNetworkCallback = new NetworkCallback(NetworkCallback.EVENT_ALL); + mNetworkCallback = newNetworkCallback(NetworkCallback.EVENT_ALL); mManager.registerNetworkCallback(networkRequest, mNetworkCallback); String key = mNetworkCallback.mId; mNetworkCallbackMap.put(key, mNetworkCallback); @@ -446,6 +481,24 @@ public class ConnectivityManagerFacade extends RpcReceiver { private NetworkRequest buildNetworkRequestFromJson(JSONObject configJson) throws JSONException { + return makeNetworkRequestBuilderFromJson(configJson).build(); + } + + private NetworkRequest buildWifiAwareNetworkRequestFromJson(JSONObject configJson) + throws JSONException { + final NetworkRequest.Builder builder = makeNetworkRequestBuilderFromJson(configJson); + if (configJson.has("NetworkSpecifier")) { + final String strSpecifier = configJson.getString("NetworkSpecifier"); + Log.d("build NetworkSpecifier" + strSpecifier); + final NetworkSpecifier specifier = WifiAwareManagerFacade.getNetworkSpecifier( + new JSONObject(strSpecifier)); + builder.setNetworkSpecifier(specifier); + } + return builder.build(); + } + + private NetworkRequest.Builder makeNetworkRequestBuilderFromJson(JSONObject configJson) + throws JSONException { NetworkRequest.Builder builder = new NetworkRequest.Builder(); if (configJson.has("ClearCapabilities")) { @@ -455,16 +508,19 @@ public class ConnectivityManagerFacade extends RpcReceiver { Log.d("build ClearCapabilities"); builder.clearCapabilities(); } - if (configJson.has("TransportType")) { - Log.d("build TransportType" + configJson.getInt("TransportType")); - builder.addTransportType(configJson.getInt("TransportType")); + if (configJson.has(ConnectivityConstants.NET_CAPABILITIES_TRANSPORT_TYPE)) { + Log.d("build TransportType" + + configJson.getInt(ConnectivityConstants.NET_CAPABILITIES_TRANSPORT_TYPE)); + builder.addTransportType( + configJson.getInt(ConnectivityConstants.NET_CAPABILITIES_TRANSPORT_TYPE)); } if (configJson.has("SignalStrength")) { Log.d("build SignalStrength" + configJson.getInt("SignalStrength")); builder.setSignalStrength(configJson.getInt("SignalStrength")); } - if (configJson.has("Capability")) { - JSONArray capabilities = configJson.getJSONArray("Capability"); + if (configJson.has(ConnectivityConstants.NET_CAPABILITIES_CAPABILITIES)) { + JSONArray capabilities = + configJson.getJSONArray(ConnectivityConstants.NET_CAPABILITIES_CAPABILITIES); for (int i = 0; i < capabilities.length(); i++) { Log.d("build Capability" + capabilities.getInt(i)); builder.addCapability(capabilities.getInt(i)); @@ -482,20 +538,14 @@ public class ConnectivityManagerFacade extends RpcReceiver { builder.setLinkDownstreamBandwidthKbps(configJson.getInt( "LinkDownstreamBandwidthKbps")); } - if (configJson.has("NetworkSpecifier")) { - Log.d("build NetworkSpecifier" + configJson.getString("NetworkSpecifier")); - builder.setNetworkSpecifier(configJson.getString( - "NetworkSpecifier")); - } - NetworkRequest networkRequest = builder.build(); - return networkRequest; + return builder; } @Rpc(description = "register a network callback") public String connectivityRegisterNetworkCallback(@RpcParameter(name = "configJson") JSONObject configJson) throws JSONException { NetworkRequest networkRequest = buildNetworkRequestFromJson(configJson); - mNetworkCallback = new NetworkCallback(NetworkCallback.EVENT_ALL); + mNetworkCallback = newNetworkCallback(NetworkCallback.EVENT_ALL); mManager.registerNetworkCallback(networkRequest, mNetworkCallback); String key = mNetworkCallback.mId; mNetworkCallbackMap.put(key, mNetworkCallback); @@ -517,7 +567,7 @@ public class ConnectivityManagerFacade extends RpcReceiver { @Rpc(description = "register a default network callback") public String connectivityRegisterDefaultNetworkCallback() { - mNetworkCallback = new NetworkCallback(NetworkCallback.EVENT_ALL); + mNetworkCallback = newNetworkCallback(NetworkCallback.EVENT_ALL); mManager.registerDefaultNetworkCallback(mNetworkCallback); String key = mNetworkCallback.mId; mNetworkCallbackMap.put(key, mNetworkCallback); @@ -528,7 +578,7 @@ public class ConnectivityManagerFacade extends RpcReceiver { public String connectivityRequestNetwork(@RpcParameter(name = "configJson") JSONObject configJson) throws JSONException { NetworkRequest networkRequest = buildNetworkRequestFromJson(configJson); - mNetworkCallback = new NetworkCallback(NetworkCallback.EVENT_ALL); + mNetworkCallback = newNetworkCallback(NetworkCallback.EVENT_ALL); mManager.requestNetwork(networkRequest, mNetworkCallback); String key = mNetworkCallback.mId; mNetworkCallbackMap.put(key, mNetworkCallback); @@ -538,23 +588,42 @@ public class ConnectivityManagerFacade extends RpcReceiver { @Rpc(description = "Request a Wi-Fi Aware network") public String connectivityRequestWifiAwareNetwork(@RpcParameter(name = "configJson") JSONObject configJson) throws JSONException { - NetworkRequest networkRequest = buildNetworkRequestFromJson(configJson); - if (networkRequest.networkCapabilities.getNetworkSpecifier() instanceof - StringNetworkSpecifier) { - String ns = - ((StringNetworkSpecifier) networkRequest.networkCapabilities - .getNetworkSpecifier()).specifier; - JSONObject j = new JSONObject(ns); - networkRequest.networkCapabilities.setNetworkSpecifier( - WifiAwareManagerFacade.getNetworkSpecifier(j)); - } - mNetworkCallback = new NetworkCallback(NetworkCallback.EVENT_ALL); + NetworkRequest networkRequest = buildWifiAwareNetworkRequestFromJson(configJson); + mNetworkCallback = newNetworkCallback(NetworkCallback.EVENT_ALL); mManager.requestNetwork(networkRequest, mNetworkCallback); String key = mNetworkCallback.mId; mNetworkCallbackMap.put(key, mNetworkCallback); return key; } + /** + * Initiates a network request {@link NetworkRequest} using {@link WifiNetworkSpecifier}. + * + * @param wNs JSONObject Dictionary of wifi network specifier parameters + * @param timeoutInMs Timeout for the request. 0 indicates no timeout. + * @throws JSONException + * @throws GeneralSecurityException + */ + @Rpc(description = "Initiates a network request using the provided network specifier") + public String connectivityRequestWifiNetwork( + @RpcParameter(name = "wifiNetworkSpecifier") JSONObject wNs, + @RpcParameter(name = "timeoutInMS") Integer timeoutInMs) + throws JSONException, GeneralSecurityException { + NetworkRequest networkRequest = new NetworkRequest.Builder() + .addTransportType(TRANSPORT_WIFI) + .setNetworkSpecifier(WifiManagerFacade.genWifiNetworkSpecifier(wNs)) + .build(); + mNetworkCallback = newNetworkCallback(NetworkCallback.EVENT_ALL); + if (timeoutInMs != 0) { + mManager.requestNetwork(networkRequest, mNetworkCallback, timeoutInMs); + } else { + mManager.requestNetwork(networkRequest, mNetworkCallback); + } + String key = mNetworkCallback.mId; + mNetworkCallbackMap.put(key, mNetworkCallback); + return key; + } + @Rpc(description = "Stop listening for connectivity changes") public void connectivityStopTrackingConnectivityStateChange() { if (mTrackingConnectivityStateChange) { @@ -598,6 +667,16 @@ public class ConnectivityManagerFacade extends RpcReceiver { return mManager.getAllNetworkInfo(); } + @Rpc(description = "Get connection status information about all network types supported by the device.") + public NetworkCapabilities[] connectivityNetworkGetAllCapabilities() { + Network[] networks = mManager.getAllNetworks(); + NetworkCapabilities[] networkCapabilties = new NetworkCapabilities[networks.length]; + for (int i = 0; i < networks.length; i++) { + networkCapabilties[i] = mManager.getNetworkCapabilities(networks[i]); + } + return networkCapabilties; + } + @Rpc(description = "Check whether the active network is connected to the Internet.") public Boolean connectivityNetworkIsConnected() { NetworkInfo current = mManager.getActiveNetworkInfo(); @@ -1039,5 +1118,8 @@ public class ConnectivityManagerFacade extends RpcReceiver { @Override public void shutdown() { connectivityStopTrackingConnectivityStateChange(); + for (NetworkCallback networkCallback : mNetworkCallbackMap.values()) { + mManager.unregisterNetworkCallback(networkCallback); + } } } diff --git a/Common/src/com/googlecode/android_scripting/facade/VpnFacade.java b/Common/src/com/googlecode/android_scripting/facade/VpnFacade.java index 732cc605..bed8cc82 100644 --- a/Common/src/com/googlecode/android_scripting/facade/VpnFacade.java +++ b/Common/src/com/googlecode/android_scripting/facade/VpnFacade.java @@ -16,50 +16,50 @@ package com.googlecode.android_scripting.facade; -import java.util.ArrayList; -import java.util.List; - -import org.json.JSONObject; +import android.app.Service; +import android.net.VpnManager; +import android.os.RemoteException; +import android.security.Credentials; +import android.security.KeyStore; +import android.security.LegacyVpnProfileStore; import com.android.internal.net.LegacyVpnInfo; import com.android.internal.net.VpnConfig; import com.android.internal.net.VpnProfile; import com.android.internal.util.ArrayUtils; + import com.google.android.collect.Lists; import com.googlecode.android_scripting.jsonrpc.RpcReceiver; import com.googlecode.android_scripting.rpc.Rpc; import com.googlecode.android_scripting.rpc.RpcParameter; -import android.app.Service; -import android.content.Context; -import android.net.IConnectivityManager; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.security.Credentials; -import android.security.KeyStore; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.List; /** - * Access NFC functions. + * Access VPN functions. */ public class VpnFacade extends RpcReceiver { private final Service mService; - private final IConnectivityManager mConService; + private final VpnManager mVpnManager; private CertInstallerHelper mCertHelper; public VpnFacade(FacadeManager manager) { super(manager); mService = manager.getService(); mCertHelper = new CertInstallerHelper(); - mConService = IConnectivityManager.Stub - .asInterface(ServiceManager.getService(Context.CONNECTIVITY_SERVICE)); + mVpnManager = mService.getSystemService(VpnManager.class); } static List<VpnProfile> loadVpnProfiles(KeyStore keyStore, int... excludeTypes) { final ArrayList<VpnProfile> result = Lists.newArrayList(); - for (String key : keyStore.list(Credentials.VPN)) { - final VpnProfile profile = VpnProfile.decode(key, keyStore.get(Credentials.VPN + key)); + for (String key : LegacyVpnProfileStore.list(Credentials.VPN)) { + final VpnProfile profile = VpnProfile.decode(key, + LegacyVpnProfileStore.get(Credentials.VPN + key)); if (profile != null && !ArrayUtils.contains(excludeTypes, profile.type)) { result.add(profile); } @@ -92,17 +92,17 @@ public class VpnFacade extends RpcReceiver { public void vpnStartLegacyVpn(@RpcParameter(name = "vpnProfile") JSONObject vpnProfile) throws RemoteException { VpnProfile profile = genLegacyVpnProfile(vpnProfile); - mConService.startLegacyVpn(profile); + mVpnManager.startLegacyVpn(profile); } @Rpc(description = "Stop the current legacy VPN connection.") public void vpnStopLegacyVpn() throws RemoteException { - mConService.prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN, mService.getUserId()); + mVpnManager.prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN, mService.getUserId()); } @Rpc(description = "Get the info object of the currently active legacy VPN connection.") public LegacyVpnInfo vpnGetLegacyVpnInfo() throws RemoteException { - return mConService.getLegacyVpnInfo(mService.getUserId()); + return mVpnManager.getLegacyVpnInfo(mService.getUserId()); } @Override diff --git a/Common/src/com/googlecode/android_scripting/facade/bluetooth/BluetoothHfpClientFacade.java b/Common/src/com/googlecode/android_scripting/facade/bluetooth/BluetoothHfpClientFacade.java index 17e7b575..8c6f93f8 100644 --- a/Common/src/com/googlecode/android_scripting/facade/bluetooth/BluetoothHfpClientFacade.java +++ b/Common/src/com/googlecode/android_scripting/facade/bluetooth/BluetoothHfpClientFacade.java @@ -28,6 +28,7 @@ import com.googlecode.android_scripting.Log; import com.googlecode.android_scripting.facade.FacadeManager; import com.googlecode.android_scripting.jsonrpc.RpcReceiver; import com.googlecode.android_scripting.rpc.Rpc; +import com.googlecode.android_scripting.rpc.RpcDefault; import com.googlecode.android_scripting.rpc.RpcParameter; import java.util.ArrayList; @@ -237,27 +238,32 @@ public class BluetoothHfpClientFacade extends RpcReceiver { return sHfpClientProfile.getAudioState(device); } + private BluetoothDevice getDevice(String deviceStr) { + if (sHfpClientProfile == null) return null; + BluetoothDevice device; + try { + device = BluetoothFacade.getDevice(sHfpClientProfile.getConnectedDevices(), deviceStr); + } catch (Exception e) { + // Do nothing since it is disconnect and this function should force disconnect. + Log.e("bluetoothHfpClientConnect getDevice failed " + e); + return null; + } + return device; + } + /** - * Start Voice Recognition on remote device + * Starts Voice Recognition on remote device * * @param deviceStr the Bluetooth MAC address of remote device - * @return True if command was sent + * @return True if command has been issued successfully */ @Rpc(description = "Start Remote device Voice Recognition through HFP Client.") public boolean bluetoothHfpClientStartVoiceRecognition( @RpcParameter(name = "device", description = "MAC address of a bluetooth device.") String deviceStr) { - if (sHfpClientProfile == null) return false; - BluetoothDevice device; - try { - device = BluetoothFacade.getDevice( - sHfpClientProfile.getConnectedDevices(), deviceStr); - } catch (Exception e) { - // Do nothing since it is disconnect and this function should force disconnect. - Log.e("bluetoothHfpClientConnect getDevice failed " + e); - return false; - } + BluetoothDevice device = getDevice(deviceStr); + if (device == null) return false; return sHfpClientProfile.startVoiceRecognition(device); } @@ -265,49 +271,89 @@ public class BluetoothHfpClientFacade extends RpcReceiver { * Stops Voice Recognition in the remote device through Bluetooth HFP client * * @param deviceStr the Bluetooth MAC address of remote device - * @return True if command was sent + * @return True if command has been issued successfully */ @Rpc(description = "Stops Remote device Voice Recognition through HFP Client.") public boolean bluetoothHfpClientStopVoiceRecognition( @RpcParameter(name = "device", description = "MAC address of a bluetooth device.") String deviceStr) { - if (sHfpClientProfile == null) return false; - BluetoothDevice device; - try { - device = BluetoothFacade.getDevice( - sHfpClientProfile.getConnectedDevices(), deviceStr); - } catch (Exception e) { - // Do nothing since it is disconnect - // and this function should force disconnect. - Log.e("bluetoothHfpClientConnect getDevice failed " + e); - return false; - } + BluetoothDevice device = getDevice(deviceStr); + if (device == null) return false; return sHfpClientProfile.stopVoiceRecognition(device); } /** + * Initiates a connection of audio channel. + * + * It setup SCO channel with remote connected Handsfree Audio Gateway device. + * + * @param deviceStr the Bluetooth MAC address of remote device + * @return True if command has been issued successfully + */ + @Rpc(description = "Initiates a connection of audio channel.") + public boolean bluetoothHfpClientConnectAudio( + @RpcParameter(name = "device", + description = "MAC address of a bluetooth device.") + String deviceStr) { + BluetoothDevice device = getDevice(deviceStr); + if (device == null) return false; + return sHfpClientProfile.connectAudio(device); + } + + /** + * Dials a call in the remote device through Bluetooth HFP Client + * + * The last number dial will be placed if the number is an empty string + * + * @param deviceStr the Bluetooth MAC address of remote device + * @param number phone number to dial, the value of null or empty string for last number redial + * @return The string of <code>{@link BluetoothHeadsetClientCall} call</code> or null if no + * device was not found. + */ + @Rpc(description = "Dials a call in the remote device through HFP Client.") + public String bluetoothHfpClientDial( + @RpcParameter(name = "device", + description = "MAC address of a bluetooth device.") String deviceStr, + @RpcParameter(name = "phone_number", description = + "phone number to dial, default for last number redial") + @RpcDefault("") String number) { + BluetoothDevice device = getDevice(deviceStr); + if (device == null) return null; + return sHfpClientProfile.dial(device, number).toString(true); + } + + /** + * Disconnects audio channel. + * + * It tears down the SCO channel from remote AuG device. + * + * @param deviceStr the Bluetooth MAC address of remote device + * @return True if command has been issued successfully + */ + @Rpc(description = "Disconnects audio channel.") + public boolean bluetoothHfpClientDisconnectAudio( + @RpcParameter(name = "device", + description = "MAC address of a bluetooth device.") + String deviceStr) { + BluetoothDevice device = getDevice(deviceStr); + if (device == null) return false; + return sHfpClientProfile.disconnectAudio(device); + } + + /** * Accepts a call in the remote device through Bluetooth HFP Client * * @param deviceStr the Bluetooth MAC address of remote device - * @return True if command was sent + * @return True if command has been issued successfully */ @Rpc(description = "Accepts a call in the remote device through HFP Client.") public boolean bluetoothHfpClientAcceptCall( @RpcParameter(name = "device", description = "MAC address of a bluetooth device.") String deviceStr) { - if (sHfpClientProfile == null) return false; - BluetoothDevice device; - try { - device = BluetoothFacade.getDevice( - sHfpClientProfile.getConnectedDevices(), deviceStr); - } catch (Exception e) { - // Do nothing since it is disconnect - // and this function should force disconnect. - Log.e("bluetoothHfpClientConnect getDevice failed " + e); - return false; - } + BluetoothDevice device = getDevice(deviceStr); + if (device == null) return false; return sHfpClientProfile.acceptCall(device, BluetoothHeadsetClient.CALL_ACCEPT_NONE); } @@ -315,24 +361,15 @@ public class BluetoothHfpClientFacade extends RpcReceiver { * Terminates all calls in the remote device through Bluetooth HFP Client * * @param deviceStr the Bluetooth MAC address of remote device - * @return True if command was sent + * @return True if command has been issued successfully */ @Rpc(description = "Terminates all calls in the remote device through HFP Client.") public boolean bluetoothHfpClientTerminateAllCalls( @RpcParameter(name = "device", description = "MAC address of a bluetooth device.") String deviceStr) { - if (sHfpClientProfile == null) return false; - BluetoothDevice device; - try { - device = BluetoothFacade.getDevice( - sHfpClientProfile.getConnectedDevices(), deviceStr); - } catch (Exception e) { - // Do nothing since it is disconnect - // and this function should force disconnect. - Log.e("bluetoothHfpClientConnect getDevice failed " + e); - return false; - } + BluetoothDevice device = getDevice(deviceStr); + if (device == null) return false; return sHfpClientProfile.terminateCall(device, null); } @@ -340,28 +377,19 @@ public class BluetoothHfpClientFacade extends RpcReceiver { * Rejects a call in the remote device through Bluetooth HFP Client * * @param deviceStr the Bluetooth MAC address of remote device - * @return True if command was sent + * @return True if command has been issued successfully */ @Rpc(description = "Rejects a call in the remote device through HFP Client.") public boolean bluetoothHfpClientRejectCall( @RpcParameter(name = "device", description = "MAC address of a bluetooth device.") String deviceStr) { - if (sHfpClientProfile == null) return false; - BluetoothDevice device; - try { - device = BluetoothFacade.getDevice( - sHfpClientProfile.getConnectedDevices(), deviceStr); - } catch (Exception e) { - // Do nothing since it is disconnect - // and this function should force disconnect. - Log.e("bluetoothHfpClientConnect getDevice failed " + e); - return false; - } + BluetoothDevice device = getDevice(deviceStr); + if (device == null) return false; return sHfpClientProfile.rejectCall(device); } @Override public void shutdown() { } -} +}
\ No newline at end of file diff --git a/Common/src/com/googlecode/android_scripting/facade/bluetooth/BluetoothSocketConnFacade.java b/Common/src/com/googlecode/android_scripting/facade/bluetooth/BluetoothSocketConnFacade.java index c08fc96a..18ca8588 100644 --- a/Common/src/com/googlecode/android_scripting/facade/bluetooth/BluetoothSocketConnFacade.java +++ b/Common/src/com/googlecode/android_scripting/facade/bluetooth/BluetoothSocketConnFacade.java @@ -33,6 +33,7 @@ import com.googlecode.android_scripting.rpc.RpcParameter; import org.apache.commons.codec.binary.Base64Codec; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.lang.reflect.Method; import java.util.HashMap; @@ -555,9 +556,19 @@ public class BluetoothSocketConnFacade extends RpcReceiver { byte bufIndex = (byte) 0x00FF; try { + + ByteArrayOutputStream tmp_array = new ByteArrayOutputStream(); for (int i = 0; i < numBuffers; i++) { // Read one buffer - byte[] readBuf = conn.readBinary(bufferSize); + while (tmp_array.size() < bufferSize) { + byte[] tmp_read = conn.readBinary(bufferSize); + if (tmp_read.length == 0) { + break; + } + tmp_array.write(tmp_read); + } + byte[] readBuf = tmp_array.toByteArray(); + tmp_array.reset(); // Make sure the contents are valid int nextInChar = 'a'; @@ -587,6 +598,9 @@ public class BluetoothSocketConnFacade extends RpcReceiver { nextInChar = getNextOutputChar(nextInChar); } Log.d("bluetoothConnectionThroughputRead: Buffer Read index=" + i); + if (bufferSize < readBuf.length) { + tmp_array.write(readBuf, bufferSize, readBuf.length - bufferSize); + } } long endTesttime = System.currentTimeMillis(); diff --git a/Common/src/com/googlecode/android_scripting/facade/bluetooth/GattClientFacade.java b/Common/src/com/googlecode/android_scripting/facade/bluetooth/GattClientFacade.java index f6edde8a..e2286724 100644 --- a/Common/src/com/googlecode/android_scripting/facade/bluetooth/GattClientFacade.java +++ b/Common/src/com/googlecode/android_scripting/facade/bluetooth/GattClientFacade.java @@ -1740,7 +1740,7 @@ public class GattClientFacade extends RpcReceiver { * @param index the bluetooth gatt index * @param minConnectionInterval minimum connection interval * @param maxConnectionInterval maximum connection interval - * @param slaveLatency maximum slave latency + * @param peripheralLatency maximum peripheral latency * @param supervisionTimeout supervision timeout * @return boolean True if successful False otherwise. * @throws Exception @@ -1750,7 +1750,7 @@ public class GattClientFacade extends RpcReceiver { @RpcParameter(name = "index") Integer index, @RpcParameter(name = "minConnectionInterval") Integer minConnectionInterval, @RpcParameter(name = "maxConnectionInterval") Integer maxConnectionInterval, - @RpcParameter(name = "slaveLatency") Integer slaveLatency, + @RpcParameter(name = "peripheralLatency") Integer peripheralLatency, @RpcParameter(name = "supervisionTimeout") Integer supervisionTimeout, @RpcParameter(name = "minConnectionEventLen") Integer minConnectionEventLen, @RpcParameter(name = "maxConnectionEventLen") Integer maxConnectionEventLen) @@ -1758,7 +1758,7 @@ public class GattClientFacade extends RpcReceiver { boolean result = false; if (mBluetoothGattList.get(index) != null) { result = mBluetoothGattList.get(index).requestLeConnectionUpdate( - minConnectionInterval, maxConnectionInterval, slaveLatency, supervisionTimeout, + minConnectionInterval, maxConnectionInterval, peripheralLatency, supervisionTimeout, minConnectionEventLen, maxConnectionEventLen); } else { throw new Exception("Invalid index input:" + index); diff --git a/Common/src/com/googlecode/android_scripting/facade/media/MediaSessionFacade.java b/Common/src/com/googlecode/android_scripting/facade/media/MediaSessionFacade.java index ad16dc9d..5b4e199b 100644 --- a/Common/src/com/googlecode/android_scripting/facade/media/MediaSessionFacade.java +++ b/Common/src/com/googlecode/android_scripting/facade/media/MediaSessionFacade.java @@ -16,19 +16,15 @@ package com.googlecode.android_scripting.facade.media; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Callable; - import android.app.Service; import android.content.ComponentName; import android.content.Context; import android.media.session.MediaController; import android.media.session.MediaSession; +import android.media.session.MediaSession.Callback; import android.media.session.MediaSessionManager; import android.media.session.MediaSessionManager.OnActiveSessionsChangedListener; import android.media.session.PlaybackState; -import android.media.session.MediaSession.Callback; import android.view.KeyEvent; import com.googlecode.android_scripting.Log; @@ -40,6 +36,10 @@ import com.googlecode.android_scripting.rpc.Rpc; import com.googlecode.android_scripting.rpc.RpcDefault; import com.googlecode.android_scripting.rpc.RpcParameter; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Callable; + /** * Expose functionalities of MediaSession related classes * like MediaSession, MediaSessionManager, MediaController. @@ -146,8 +146,8 @@ public class MediaSessionFacade extends RpcReceiver { } KeyEvent keyDown = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode); KeyEvent keyUp = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode); - mManager.dispatchMediaKeyEvent(keyDown); - mManager.dispatchMediaKeyEvent(keyUp); + mManager.dispatchMediaKeyEvent(keyDown, false); + mManager.dispatchMediaKeyEvent(keyUp, false); } private MediaController getMediaController(int idx) { diff --git a/Common/src/com/googlecode/android_scripting/facade/net/IpSecManagerFacade.java b/Common/src/com/googlecode/android_scripting/facade/net/IpSecManagerFacade.java index d0a443f4..a856a1b2 100644 --- a/Common/src/com/googlecode/android_scripting/facade/net/IpSecManagerFacade.java +++ b/Common/src/com/googlecode/android_scripting/facade/net/IpSecManagerFacade.java @@ -18,6 +18,7 @@ package com.googlecode.android_scripting.facade.net; import android.app.Service; import android.content.Context; +import android.net.InetAddresses; import android.net.IpSecAlgorithm; import android.net.IpSecManager; import android.net.IpSecManager.ResourceUnavailableException; @@ -26,7 +27,6 @@ import android.net.IpSecManager.SpiUnavailableException; import android.net.IpSecManager.UdpEncapsulationSocket; import android.net.IpSecTransform; import android.net.IpSecTransform.Builder; -import android.net.NetworkUtils; import com.google.common.io.BaseEncoding; import com.googlecode.android_scripting.Log; @@ -315,7 +315,7 @@ public class IpSecManagerFacade extends RpcReceiver { String addr, String udpEncapSockId) { IpSecTransform transform = null; - InetAddress inetAddr = NetworkUtils.numericToInetAddress(addr); + InetAddress inetAddr = InetAddresses.parseNumericAddress(addr); UdpEncapsulationSocket udpEncapSocket = sUdpEncapHashMap.get(udpEncapSockId); SecurityParameterIndex spi = sSpiHashMap.get(spiId); if (spi == null) { @@ -385,7 +385,7 @@ public class IpSecManagerFacade extends RpcReceiver { public String ipSecAllocateSecurityParameterIndex( @RpcParameter(name = "addr") String addr, @RpcParameter(name = "requestedSpi") @RpcOptional Integer requestedSpi) { - InetAddress inetAddr = NetworkUtils.numericToInetAddress(addr); + InetAddress inetAddr = InetAddresses.parseNumericAddress(addr); SecurityParameterIndex spi = null; if (requestedSpi == null) { spi = allocateSpi(inetAddr); diff --git a/Common/src/com/googlecode/android_scripting/facade/net/SocketFacade.java b/Common/src/com/googlecode/android_scripting/facade/net/SocketFacade.java index b57f1fbb..4bcd60c1 100644 --- a/Common/src/com/googlecode/android_scripting/facade/net/SocketFacade.java +++ b/Common/src/com/googlecode/android_scripting/facade/net/SocketFacade.java @@ -16,7 +16,7 @@ package com.googlecode.android_scripting.facade.net; -import android.net.NetworkUtils; +import android.net.InetAddresses; import android.os.ParcelFileDescriptor; import android.system.ErrnoException; import android.system.Os; @@ -157,8 +157,8 @@ public class SocketFacade extends RpcReceiver { String local, Integer localPort) { try { - InetAddress remoteAddr = NetworkUtils.numericToInetAddress(remote); - InetAddress localAddr = NetworkUtils.numericToInetAddress(local); + InetAddress remoteAddr = InetAddresses.parseNumericAddress(remote); + InetAddress localAddr = InetAddresses.parseNumericAddress(local); Socket socket = new Socket(remoteAddr, remotePort.intValue(), localAddr, localPort.intValue()); socket.setSoLinger(true, 0); @@ -209,7 +209,7 @@ public class SocketFacade extends RpcReceiver { @Rpc(description = "Open TCP server socket and accept connection") public String openTcpServerSocket(String addr, Integer port) { try { - InetAddress localAddr = NetworkUtils.numericToInetAddress(addr); + InetAddress localAddr = InetAddresses.parseNumericAddress(addr); ServerSocket serverSocket = new ServerSocket(port.intValue(), 10, localAddr); String id = getServerSocketId(serverSocket); sServerSocketHashMap.put(id, serverSocket); @@ -402,13 +402,14 @@ public class SocketFacade extends RpcReceiver { /** * Open datagram socket using java.net.DatagramSocket + * * @param addr : IP addr to use * @param port : port to open socket on * @return Hash key of {@link DatagramSocket} */ @Rpc(description = "Open datagram socket") public String openDatagramSocket(String addr, Integer port) { - InetAddress localAddr = NetworkUtils.numericToInetAddress(addr); + InetAddress localAddr = InetAddresses.parseNumericAddress(addr); try { DatagramSocket socket = new DatagramSocket(port.intValue(), localAddr); socket.setSoTimeout(SOCK_TIMEOUT); @@ -458,7 +459,7 @@ public class SocketFacade extends RpcReceiver { Integer port) { byte[] buf = message.getBytes(); try { - InetAddress remoteAddr = NetworkUtils.numericToInetAddress(addr); + InetAddress remoteAddr = InetAddresses.parseNumericAddress(addr); DatagramSocket socket = sDatagramSocketHashMap.get(datagramSocketId); DatagramPacket pkt = new DatagramPacket(buf, buf.length, remoteAddr, port.intValue()); socket.send(pkt); @@ -505,7 +506,7 @@ public class SocketFacade extends RpcReceiver { public String openSocket(Integer domain, Integer type, String addr, Integer port) { try { FileDescriptor fd = Os.socket(domain, type, 0); - InetAddress localAddr = NetworkUtils.numericToInetAddress(addr); + InetAddress localAddr = InetAddresses.parseNumericAddress(addr); Os.bind(fd, localAddr, port.intValue()); String id = getFileDescriptorId(fd); sFileDescriptorHashMap.put(id, fd); @@ -545,7 +546,7 @@ public class SocketFacade extends RpcReceiver { public Boolean sendDataOverSocket( String remoteAddr, Integer remotePort, String message, String id) { FileDescriptor fd = sFileDescriptorHashMap.get(id); - InetAddress remote = NetworkUtils.numericToInetAddress(remoteAddr); + InetAddress remote = InetAddresses.parseNumericAddress(remoteAddr); try { byte [] data = new String(message).getBytes(StandardCharsets.UTF_8); int bytes = Os.sendto(fd, data, 0, data.length, 0, remote, remotePort.intValue()); @@ -604,7 +605,7 @@ public class SocketFacade extends RpcReceiver { public Boolean connectSocket(String id, String addr, Integer port) { FileDescriptor fd = sFileDescriptorHashMap.get(id); try { - InetAddress remoteAddr = NetworkUtils.numericToInetAddress(addr); + InetAddress remoteAddr = InetAddresses.parseNumericAddress(addr); Os.connect(fd, remoteAddr, port.intValue()); return true; } catch (SocketException | ErrnoException e) { diff --git a/Common/src/com/googlecode/android_scripting/facade/telephony/SmsFacade.java b/Common/src/com/googlecode/android_scripting/facade/telephony/SmsFacade.java index fa9170a6..1de17161 100644 --- a/Common/src/com/googlecode/android_scripting/facade/telephony/SmsFacade.java +++ b/Common/src/com/googlecode/android_scripting/facade/telephony/SmsFacade.java @@ -741,7 +741,7 @@ public class SmsFacade extends RpcReceiver { private PendingIntent createBroadcastPendingIntent(String intentAction, Uri messageUri) { Intent intent = new Intent(intentAction, messageUri); - return PendingIntent.getBroadcast(mService, 0, intent, 0); + return PendingIntent.getBroadcast(mService, 0, intent, PendingIntent.FLAG_MUTABLE); } private static String getSmsFailureReason(int resultCode) { diff --git a/Common/src/com/googlecode/android_scripting/facade/telephony/TelephonyConstants.java b/Common/src/com/googlecode/android_scripting/facade/telephony/TelephonyConstants.java index ecbec0dd..d5e96335 100644 --- a/Common/src/com/googlecode/android_scripting/facade/telephony/TelephonyConstants.java +++ b/Common/src/com/googlecode/android_scripting/facade/telephony/TelephonyConstants.java @@ -188,6 +188,7 @@ public class TelephonyConstants { public static final String RAT_TD_SCDMA = "TD_SCDMA"; public static final String RAT_GLOBAL = "GLOBAL"; public static final String RAT_LTE_CA = "LTE_CA"; + public static final String RAT_NR = "NR"; public static final String RAT_UNKNOWN = "UNKNOWN"; /** @@ -228,6 +229,15 @@ public class TelephonyConstants { public static final String DATA_STATE_UNKNOWN = "UNKNOWN"; /** + * Constant for Override Network Type + * **/ + public static final String OVERRIDE_NETWORK_TYPE_NONE = "NONE"; + public static final String OVERRIDE_NETWORK_TYPE_LTE_CA = "LTE_CA"; + public static final String OVERRIDE_NETWORK_TYPE_LTE_ADVANCED_PRO = "LTE_ADVANCED_PRO"; + public static final String OVERRIDE_NETWORK_TYPE_NR_NSA = "NR_NSA"; + public static final String OVERRIDE_NETWORK_TYPE_NR_ADVANCED = "NR_MMWAVE"; + + /** * Constant for Telephony Manager Call State * **/ public static final String TELEPHONY_STATE_RINGING = "RINGING"; @@ -317,6 +327,17 @@ public class TelephonyConstants { public static final String NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA = "NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA"; public static final String NETWORK_MODE_TDSCDMA_CDMA_EVDO_GSM_WCDMA = "NETWORK_MODE_TDSCDMA_CDMA_EVDO_GSM_WCDMA"; public static final String NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA = "NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA"; + public static final String NETWORK_MODE_NR_LTE_GSM_WCDMA = "NETWORK_MODE_NR_LTE_GSM_WCDMA"; + public static final String NETWORK_MODE_NR_ONLY = "NETWORK_MODE_NR_ONLY"; + public static final String NETWORK_MODE_NR_LTE = "NETWORK_MODE_NR_LTE"; + public static final String NETWORK_MODE_NR_LTE_CDMA_EVDO = "NETWORK_MODE_NR_LTE_CDMA_EVDO"; + public static final String NETWORK_MODE_NR_LTE_CDMA_EVDO_GSM_WCDMA = "NETWORK_MODE_NR_LTE_CDMA_EVDO_GSM_WCDMA"; + public static final String NETWORK_MODE_NR_LTE_WCDMA = "NETWORK_MODE_NR_LTE_WCDMA"; + public static final String NETWORK_MODE_NR_LTE_TDSCDMA = "NETWORK_MODE_NR_LTE_TDSCDMA"; + public static final String NETWORK_MODE_NR_LTE_TDSCDMA_GSM = "NETWORK_MODE_NR_LTE_TDSCDMA_GSM"; + public static final String NETWORK_MODE_NR_LTE_TDSCDMA_WCDMA = "NETWORK_MODE_NR_LTE_TDSCDMA_WCDMA"; + public static final String NETWORK_MODE_NR_LTE_TDSCDMA_GSM_WCDMA = "NETWORK_MODE_NR_LTE_TDSCDMA_GSM_WCDMA"; + public static final String NETWORK_MODE_NR_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA = "NETWORK_MODE_NR_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA"; public static final String NETWORK_MODE_INVALID = "INVALID"; /** @@ -373,6 +394,7 @@ public class TelephonyConstants { public static final String EventPreciseStateChanged = "PreciseStateChanged"; public static final String EventDataConnectionRealTimeInfoChanged = "DataConnectionRealTimeInfoChanged"; public static final String EventDataConnectionStateChanged = "DataConnectionStateChanged"; + public static final String EventDisplayInfoChanged = "DisplayInfoChanged"; public static final String EventActiveDataSubIdChanged = "ActiveDataSubIdChanged"; public static final String EventServiceStateChanged = "ServiceStateChanged"; public static final String EventSignalStrengthChanged = "SignalStrengthChanged"; @@ -438,6 +460,13 @@ public class TelephonyConstants { public static final String DATA_CONNECTION_STATE = "dataConnectionState"; } + public static class DisplayInfoContainer { + public static final String TIME = "time"; + public static final String NETWORK = "network"; + public static final String OVERRIDE = "override"; + public static final String SUBSCRIPTION_ID = "subscriptionId"; + } + public static class ServiceStateContainer { public static final String VOICE_REG_STATE = "voiceRegState"; public static final String VOICE_NETWORK_TYPE = "voiceNetworkType"; @@ -472,7 +501,7 @@ public class TelephonyConstants { public static final String IS_DATA_ROAMING_FROM_REGISTRATION = "isDataRoamingFromRegistration"; public static final String IS_USING_CARRIER_AGGREGATION = "isUsingCarrierAggregation"; - public static final String LTE_EARFCN_RSRP_BOOST = "lteEarfcnRsrpBoost"; + public static final String LTE_EARFCN_RSRP_BOOST = "LteEarfcnRsrpBoost"; } public static class MessageWaitingIndicatorContainer { diff --git a/Common/src/com/googlecode/android_scripting/facade/telephony/TelephonyEvents.java b/Common/src/com/googlecode/android_scripting/facade/telephony/TelephonyEvents.java index 7021475a..2e394fab 100644 --- a/Common/src/com/googlecode/android_scripting/facade/telephony/TelephonyEvents.java +++ b/Common/src/com/googlecode/android_scripting/facade/telephony/TelephonyEvents.java @@ -20,6 +20,7 @@ import android.telephony.DataConnectionRealTimeInfo; import android.telephony.PhysicalChannelConfig; import android.telephony.PreciseCallState; import android.telephony.ServiceState; +import android.telephony.TelephonyDisplayInfo; import com.googlecode.android_scripting.jsonrpc.JsonSerializable; @@ -267,6 +268,52 @@ public class TelephonyEvents { } } + public static class DisplayInfoChangedEvent implements JsonSerializable { + private TelephonyDisplayInfo mDisplayInfoString; + private int mSubscriptionId; + private String mOverrideDataNetworkType; + private String mDataNetworkType; + + DisplayInfoChangedEvent(TelephonyDisplayInfo DisplayInfoString, int subscriptionId) { + mDisplayInfoString = DisplayInfoString; + mSubscriptionId = subscriptionId; + mOverrideDataNetworkType = TelephonyUtils.getDisplayInfoString( + DisplayInfoString.getOverrideNetworkType()); + mDataNetworkType = TelephonyUtils.getNetworkTypeString( + DisplayInfoString.getNetworkType()); + } + + public String getOverrideDataNetworkType() { + return mOverrideDataNetworkType; + } + + public int getSubscriptionId() { + return mSubscriptionId; + } + + public String getDataNetworkType() { + return mDataNetworkType; + } + + public JSONObject toJSON() throws JSONException { + JSONObject displayInfoState = new JSONObject(); + + displayInfoState.put( + TelephonyConstants.DisplayInfoContainer.OVERRIDE, + mOverrideDataNetworkType); + + displayInfoState.put( + TelephonyConstants.DisplayInfoContainer.NETWORK, + mDataNetworkType); + + displayInfoState.put( + TelephonyConstants.DisplayInfoContainer.SUBSCRIPTION_ID, + mSubscriptionId); + + return displayInfoState; + } + } + public static class PhysicalChannelConfigChangedEvent implements JsonSerializable { private final List<PhysicalChannelConfig> mConfigs; @@ -284,7 +331,7 @@ public class TelephonyEvents { JSONObject cfg = new JSONObject(); cfg.put( TelephonyConstants.PhysicalChannelConfigContainer.CELL_BANDWIDTH_DOWNLINK, - c.getCellBandwidthDownlink()); + c.getCellBandwidthDownlinkKhz()); cfg.put( TelephonyConstants.PhysicalChannelConfigContainer.CONNECTION_STATUS, c.getConnectionStatus()); diff --git a/Common/src/com/googlecode/android_scripting/facade/telephony/TelephonyManagerFacade.java b/Common/src/com/googlecode/android_scripting/facade/telephony/TelephonyManagerFacade.java index a338402b..e60e5f15 100644 --- a/Common/src/com/googlecode/android_scripting/facade/telephony/TelephonyManagerFacade.java +++ b/Common/src/com/googlecode/android_scripting/facade/telephony/TelephonyManagerFacade.java @@ -55,6 +55,8 @@ import com.googlecode.android_scripting.facade.telephony.TelephonyStateListeners import com.googlecode.android_scripting.facade.telephony.TelephonyStateListeners .DataConnectionStateChangeListener; import com.googlecode.android_scripting.facade.telephony.TelephonyStateListeners + .DisplayInfoStateChangeListener; +import com.googlecode.android_scripting.facade.telephony.TelephonyStateListeners .ServiceStateChangeListener; import com.googlecode.android_scripting.facade.telephony.TelephonyStateListeners .SignalStrengthChangeListener; @@ -303,6 +305,28 @@ public class TelephonyManagerFacade extends RpcReceiver { return true; } + @Rpc(description = "Starts tracking display info change" + + "for default subscription ID.") + public Boolean telephonyStartTrackingDisplayInfoChange() { + return telephonyStartTrackingDisplayInfoChangeForSubscription( + SubscriptionManager.DEFAULT_SUBSCRIPTION_ID); + } + + @Rpc(description = "Starts tracking display info change" + + "for specified subscription ID.") + public Boolean telephonyStartTrackingDisplayInfoChangeForSubscription( + @RpcParameter(name = "subId") Integer subId) { + StateChangeListener listener = getStateChangeListenerForSubscription(subId, true); + if(listener == null) { + Log.e("Invalid subscription ID"); + return false; + } + mTelephonyManager.createForSubscriptionId(subId).listen( + listener.mDisplayInfoStateChangeListener, + PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED); + return true; + } + @Rpc(description = "Turn on/off precise listening on fore/background or" + " ringing calls for default voice subscription ID.") public Boolean telephonyAdjustPreciseCallStateListenLevel( @@ -381,6 +405,28 @@ public class TelephonyManagerFacade extends RpcReceiver { return true; } + @Rpc(description = "Stops tracking display info change " + + "for default subscription ID.") + public Boolean telephonyStopTrackingDisplayInfoChange() { + return telephonyStopTrackingDisplayInfoChangeForSubscription( + SubscriptionManager.DEFAULT_SUBSCRIPTION_ID); + } + + @Rpc(description = "Stops tracking display info change " + + "for specified subscription ID.") + public Boolean telephonyStopTrackingDisplayInfoChangeForSubscription( + @RpcParameter(name = "subId") Integer subId) { + StateChangeListener listener = getStateChangeListenerForSubscription(subId, false); + if(listener == null) { + Log.e("Invalid subscription ID"); + return false; + } + mTelephonyManager.createForSubscriptionId(subId).listen( + listener.mDisplayInfoStateChangeListener, + PhoneStateListener.LISTEN_NONE); + return true; + } + @Rpc(description = "Stops tracking call state change " + "for default voice subscription ID.") public Boolean telephonyStopTrackingCallStateChange() { @@ -756,7 +802,12 @@ public class TelephonyManagerFacade extends RpcReceiver { public boolean telephonySetAlwaysAllowMmsData( @RpcParameter(name = "subId") Integer subId, @RpcParameter(name = "alwaysAllow") Boolean alwaysAllow) { - return mTelephonyManager.createForSubscriptionId(subId).setAlwaysAllowMmsData(alwaysAllow); + boolean wasAlwaysAllow = mTelephonyManager.isMobileDataPolicyEnabled( + TelephonyManager.MOBILE_DATA_POLICY_MMS_ALWAYS_ALLOWED); + mTelephonyManager.createForSubscriptionId(subId) + .setMobileDataPolicyEnabled( + TelephonyManager.MOBILE_DATA_POLICY_MMS_ALWAYS_ALLOWED, alwaysAllow); + return wasAlwaysAllow == alwaysAllow; } /** @@ -1506,6 +1557,7 @@ public class TelephonyManagerFacade extends RpcReceiver { public CellInfoChangeListener mCellInfoChangeListener; public DataConnectionStateChangeListener mDataConnectionStateChangeListener; public ActiveDataSubIdChangeListener mActiveDataSubIdChangeListener; + public DisplayInfoStateChangeListener mDisplayInfoStateChangeListener; public DataConnectionRealTimeInfoChangeListener mDataConnectionRTInfoChangeListener; public VoiceMailStateChangeListener mVoiceMailStateChangeListener; @@ -1520,6 +1572,9 @@ public class TelephonyManagerFacade extends RpcReceiver { mActiveDataSubIdChangeListener = new ActiveDataSubIdChangeListener( mEventFacade, mTelephonyManager, subId, mService.getMainLooper()); + mDisplayInfoStateChangeListener = + new DisplayInfoStateChangeListener( + mEventFacade, mTelephonyManager, subId, mService.getMainLooper()); mCallStateChangeListener = new CallStateChangeListener(mEventFacade, subId, mService.getMainLooper()); mCellInfoChangeListener = @@ -1545,6 +1600,9 @@ public class TelephonyManagerFacade extends RpcReceiver { mActiveDataSubIdChangeListener, PhoneStateListener.LISTEN_NONE); mTelephonyManager.listen( + mDisplayInfoStateChangeListener, + PhoneStateListener.LISTEN_NONE); + mTelephonyManager.listen( mCellInfoChangeListener, PhoneStateListener.LISTEN_NONE); mTelephonyManager.listen( diff --git a/Common/src/com/googlecode/android_scripting/facade/telephony/TelephonyStateListeners.java b/Common/src/com/googlecode/android_scripting/facade/telephony/TelephonyStateListeners.java index e06af17a..b13b66cd 100644 --- a/Common/src/com/googlecode/android_scripting/facade/telephony/TelephonyStateListeners.java +++ b/Common/src/com/googlecode/android_scripting/facade/telephony/TelephonyStateListeners.java @@ -24,6 +24,7 @@ import android.telephony.PreciseCallState; import android.telephony.ServiceState; import android.telephony.SignalStrength; import android.telephony.SubscriptionManager; +import android.telephony.TelephonyDisplayInfo; import android.telephony.TelephonyManager; import com.googlecode.android_scripting.facade.EventFacade; @@ -217,6 +218,45 @@ public class TelephonyStateListeners { } } + public static class DisplayInfoStateChangeListener extends PhoneStateListener { + + private final EventFacade mEventFacade; + private final TelephonyManager mTelephonyManager; + public static final int sListeningStates = + PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED; + public int subscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; + + public DisplayInfoStateChangeListener(EventFacade ef, TelephonyManager tm) { + super(); + mEventFacade = ef; + mTelephonyManager = tm; + subscriptionId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID; + } + + public DisplayInfoStateChangeListener(EventFacade ef, TelephonyManager tm, int subId) { + super(); + mEventFacade = ef; + mTelephonyManager = tm; + subscriptionId = subId; + } + + public DisplayInfoStateChangeListener( + EventFacade ef, TelephonyManager tm, int subId, Looper looper) { + super(looper); + mEventFacade = ef; + mTelephonyManager = tm; + subscriptionId = subId; + } + + @Override + public void onDisplayInfoChanged(TelephonyDisplayInfo mTelephonyDisplayInfo) { + mEventFacade.postEvent( + TelephonyConstants.EventDisplayInfoChanged, + new TelephonyEvents.DisplayInfoChangedEvent( + mTelephonyDisplayInfo, subscriptionId)); + } + } + public static class ServiceStateChangeListener extends PhoneStateListener { private final EventFacade mEventFacade; diff --git a/Common/src/com/googlecode/android_scripting/facade/telephony/TelephonyUtils.java b/Common/src/com/googlecode/android_scripting/facade/telephony/TelephonyUtils.java index 3b0b4364..7af51cbe 100644 --- a/Common/src/com/googlecode/android_scripting/facade/telephony/TelephonyUtils.java +++ b/Common/src/com/googlecode/android_scripting/facade/telephony/TelephonyUtils.java @@ -15,16 +15,20 @@ */ package com.googlecode.android_scripting.facade.telephony; -import com.android.ims.ImsConfig; -import com.android.internal.telephony.RILConstants; -import com.googlecode.android_scripting.Log; + import android.telecom.TelecomManager; import android.telephony.DataConnectionRealTimeInfo; import android.telephony.PreciseCallState; import android.telephony.ServiceState; +import android.telephony.TelephonyDisplayInfo; import android.telephony.TelephonyManager; import android.telephony.VoLteServiceState; +import com.android.ims.ImsConfig; +import com.android.internal.telephony.RILConstants; + +import com.googlecode.android_scripting.Log; + /** * Telephony utility functions */ @@ -189,6 +193,23 @@ public class TelephonyUtils { return TelephonyConstants.DATA_STATE_UNKNOWN; } + public static String getDisplayInfoString(int state) { + switch (state) { + case TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE: + return TelephonyConstants.OVERRIDE_NETWORK_TYPE_NONE; + case TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_CA: + return TelephonyConstants.OVERRIDE_NETWORK_TYPE_LTE_CA; + case TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_ADVANCED_PRO: + return TelephonyConstants.OVERRIDE_NETWORK_TYPE_LTE_ADVANCED_PRO; + case TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA: + return TelephonyConstants.OVERRIDE_NETWORK_TYPE_NR_NSA; + case TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED: + return TelephonyConstants.OVERRIDE_NETWORK_TYPE_NR_ADVANCED; + } + Log.d("getDisplayInfoStateString error. int: " + state); + return TelephonyConstants.OVERRIDE_NETWORK_TYPE_NONE; + } + public static int getNetworkModeIntfromString(String networkMode) { switch (networkMode) { case TelephonyConstants.NETWORK_MODE_WCDMA_PREF: @@ -237,6 +258,28 @@ public class TelephonyUtils { return RILConstants.NETWORK_MODE_TDSCDMA_CDMA_EVDO_GSM_WCDMA; case TelephonyConstants.NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA: return RILConstants.NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA; + case TelephonyConstants.NETWORK_MODE_NR_LTE_GSM_WCDMA: + return RILConstants.NETWORK_MODE_NR_LTE_GSM_WCDMA; + case TelephonyConstants.NETWORK_MODE_NR_ONLY: + return RILConstants.NETWORK_MODE_NR_ONLY; + case TelephonyConstants.NETWORK_MODE_NR_LTE: + return RILConstants.NETWORK_MODE_NR_LTE; + case TelephonyConstants.NETWORK_MODE_NR_LTE_CDMA_EVDO: + return RILConstants.NETWORK_MODE_NR_LTE_CDMA_EVDO; + case TelephonyConstants.NETWORK_MODE_NR_LTE_CDMA_EVDO_GSM_WCDMA: + return RILConstants.NETWORK_MODE_NR_LTE_CDMA_EVDO_GSM_WCDMA; + case TelephonyConstants.NETWORK_MODE_NR_LTE_WCDMA: + return RILConstants.NETWORK_MODE_NR_LTE_WCDMA; + case TelephonyConstants.NETWORK_MODE_NR_LTE_TDSCDMA: + return RILConstants.NETWORK_MODE_NR_LTE_TDSCDMA; + case TelephonyConstants.NETWORK_MODE_NR_LTE_TDSCDMA_GSM: + return RILConstants.NETWORK_MODE_NR_LTE_TDSCDMA_GSM; + case TelephonyConstants.NETWORK_MODE_NR_LTE_TDSCDMA_WCDMA: + return RILConstants.NETWORK_MODE_NR_LTE_TDSCDMA_WCDMA; + case TelephonyConstants.NETWORK_MODE_NR_LTE_TDSCDMA_GSM_WCDMA: + return RILConstants.NETWORK_MODE_NR_LTE_TDSCDMA_GSM_WCDMA; + case TelephonyConstants.NETWORK_MODE_NR_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA: + return RILConstants.NETWORK_MODE_NR_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA; } Log.d("getNetworkModeIntfromString error. String: " + networkMode); return RILConstants.RIL_ERRNO_INVALID_RESPONSE; @@ -290,6 +333,28 @@ public class TelephonyUtils { return TelephonyConstants.NETWORK_MODE_TDSCDMA_CDMA_EVDO_GSM_WCDMA; case RILConstants.NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA: return TelephonyConstants.NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA; + case RILConstants.NETWORK_MODE_NR_LTE_GSM_WCDMA: + return TelephonyConstants.NETWORK_MODE_NR_LTE_GSM_WCDMA; + case RILConstants.NETWORK_MODE_NR_ONLY: + return TelephonyConstants.NETWORK_MODE_NR_ONLY; + case RILConstants.NETWORK_MODE_NR_LTE: + return TelephonyConstants.NETWORK_MODE_NR_LTE; + case RILConstants.NETWORK_MODE_NR_LTE_CDMA_EVDO: + return TelephonyConstants.NETWORK_MODE_NR_LTE_CDMA_EVDO; + case RILConstants.NETWORK_MODE_NR_LTE_CDMA_EVDO_GSM_WCDMA: + return TelephonyConstants.NETWORK_MODE_NR_LTE_CDMA_EVDO_GSM_WCDMA; + case RILConstants.NETWORK_MODE_NR_LTE_WCDMA: + return TelephonyConstants.NETWORK_MODE_NR_LTE_WCDMA; + case RILConstants.NETWORK_MODE_NR_LTE_TDSCDMA: + return TelephonyConstants.NETWORK_MODE_NR_LTE_TDSCDMA; + case RILConstants.NETWORK_MODE_NR_LTE_TDSCDMA_GSM: + return TelephonyConstants.NETWORK_MODE_NR_LTE_TDSCDMA_GSM; + case RILConstants.NETWORK_MODE_NR_LTE_TDSCDMA_WCDMA: + return TelephonyConstants.NETWORK_MODE_NR_LTE_TDSCDMA_WCDMA; + case RILConstants.NETWORK_MODE_NR_LTE_TDSCDMA_GSM_WCDMA: + return TelephonyConstants.NETWORK_MODE_NR_LTE_TDSCDMA_GSM_WCDMA; + case RILConstants.NETWORK_MODE_NR_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA: + return TelephonyConstants.NETWORK_MODE_NR_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA; } Log.d("getNetworkModeStringfromInt error. Int: " + networkMode); return TelephonyConstants.NETWORK_MODE_INVALID; @@ -335,6 +400,8 @@ public class TelephonyUtils { return TelephonyConstants.RAT_IDEN; case TelephonyManager.NETWORK_TYPE_LTE_CA: return TelephonyConstants.RAT_LTE_CA; + case TelephonyManager.NETWORK_TYPE_NR: + return TelephonyConstants.RAT_NR; } return TelephonyConstants.RAT_UNKNOWN; } diff --git a/Common/src/com/googlecode/android_scripting/facade/wifi/WifiAwareManagerFacade.java b/Common/src/com/googlecode/android_scripting/facade/wifi/WifiAwareManagerFacade.java index af07b3cb..c690a38e 100644 --- a/Common/src/com/googlecode/android_scripting/facade/wifi/WifiAwareManagerFacade.java +++ b/Common/src/com/googlecode/android_scripting/facade/wifi/WifiAwareManagerFacade.java @@ -882,6 +882,16 @@ public class WifiAwareManagerFacade extends RpcReceiver { mResults.putString("messageAsString", new String(message)); postEvent("WifiAwareSessionOnMessageReceived", mResults); } + + @Override + public void onServiceLost(PeerHandle peerHandle, @WifiAwareManager.DiscoveryLostReasonCode + int reason) { + Bundle mResults = new Bundle(); + mResults.putInt("discoverySessionId", mDiscoverySessionId); + mResults.putInt("peerId", peerHandle.peerId); + mResults.putInt("lostReason", reason); + postEvent("WifiAwareSessionOnServiceLost", mResults); + } } class WifiAwareRangingListener implements RttManager.RttListener { diff --git a/Common/src/com/googlecode/android_scripting/facade/wifi/WifiManagerFacade.java b/Common/src/com/googlecode/android_scripting/facade/wifi/WifiManagerFacade.java index 97b6b0e6..7a69b4bb 100755 --- a/Common/src/com/googlecode/android_scripting/facade/wifi/WifiManagerFacade.java +++ b/Common/src/com/googlecode/android_scripting/facade/wifi/WifiManagerFacade.java @@ -16,10 +16,15 @@ package com.googlecode.android_scripting.facade.wifi; +import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static android.net.wifi.WifiScanner.WIFI_BAND_24_GHZ; +import static android.net.wifi.WifiScanner.WIFI_BAND_5_GHZ; import static com.googlecode.android_scripting.jsonrpc.JsonBuilder.build; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.Service; import android.content.BroadcastReceiver; import android.content.Context; @@ -30,11 +35,13 @@ import android.net.ConnectivityManager.NetworkCallback; import android.net.DhcpInfo; import android.net.MacAddress; import android.net.Network; +import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.NetworkRequest; import android.net.NetworkSpecifier; import android.net.Uri; +import android.net.wifi.CoexUnsafeChannel; import android.net.wifi.EasyConnectStatusCallback; import android.net.wifi.ScanResult; import android.net.wifi.SoftApCapability; @@ -49,6 +56,7 @@ import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.net.wifi.WifiManager.NetworkRequestMatchCallback; import android.net.wifi.WifiManager.NetworkRequestUserSelectionCallback; +import android.net.wifi.WifiManager.SubsystemRestartTrackingCallback; import android.net.wifi.WifiManager.WifiLock; import android.net.wifi.WifiNetworkSpecifier; import android.net.wifi.WifiNetworkSuggestion; @@ -67,8 +75,11 @@ import android.provider.Settings.SettingNotFoundException; import android.text.TextUtils; import android.util.Base64; import android.util.SparseArray; +import android.util.SparseIntArray; + import com.android.internal.annotations.GuardedBy; +import com.android.modules.utils.build.SdkLevel; import com.googlecode.android_scripting.Log; import com.googlecode.android_scripting.facade.EventFacade; @@ -101,8 +112,8 @@ import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.CountDownLatch; @@ -133,15 +144,17 @@ public class WifiManagerFacade extends RpcReceiver { private final WifiScanResultsReceiver mWifiScanResultsReceiver; private final WifiStateChangeReceiver mStateChangeReceiver; private final WifiNetworkSuggestionStateChangeReceiver mNetworkSuggestionStateChangeReceiver; + private SubsystemRestartTrackingCallbackFacade mSubsystemRestartTrackingCallback = null; private final HandlerThread mCallbackHandlerThread; private final Object mCallbackLock = new Object(); - private final Map<NetworkSpecifier, NetworkCallback> mNetworkCallbacks = new HashMap<>(); private boolean mTrackingWifiStateChange; private boolean mTrackingTetherStateChange; private boolean mTrackingNetworkSuggestionStateChange; @GuardedBy("mCallbackLock") private NetworkRequestUserSelectionCallback mNetworkRequestUserSelectionCallback; private final SparseArray<SoftApCallbackImp> mSoftapCallbacks; + // This is null if SdkLevel is not at least S + @Nullable private WifiManager.CoexCallback mCoexCallback; private final BroadcastReceiver mTetherStateReceiver = new BroadcastReceiver() { @Override @@ -208,25 +221,6 @@ public class WifiManagerFacade extends RpcReceiver { } }; - private final class NetworkCallbackImpl extends NetworkCallback { - private static final String EVENT_TAG = mEventType + "NetworkCallback"; - - @Override - public void onAvailable(Network network) { - mEventFacade.postEvent(EVENT_TAG + "OnAvailable", mWifi.getConnectionInfo()); - } - - @Override - public void onUnavailable() { - mEventFacade.postEvent(EVENT_TAG + "OnUnavailable", null); - } - - @Override - public void onLost(Network network) { - mEventFacade.postEvent(EVENT_TAG + "OnLost", null); - } - }; - private static class SoftApCallbackImp implements WifiManager.SoftApCallback { // A monotonic increasing counter for softap callback ids. private static int sCount = 0; @@ -252,21 +246,36 @@ public class WifiManagerFacade extends RpcReceiver { @Override public void onConnectedClientsChanged(List<WifiClient> clients) { - ArrayList<String> macAddresses = new ArrayList<>(); - clients.forEach(x -> macAddresses.add(x.getMacAddress().toString())); + ArrayList<MacAddress> macAddresses = new ArrayList<>(); + clients.forEach(x -> macAddresses.add(x.getMacAddress())); Bundle msg = new Bundle(); msg.putInt("NumClients", clients.size()); - msg.putStringArrayList("MacAddresses", macAddresses); + msg.putParcelableArrayList("MacAddresses", macAddresses); mEventFacade.postEvent(mEventStr + "OnNumClientsChanged", msg); mEventFacade.postEvent(mEventStr + "OnConnectedClientsChanged", clients); } @Override + public void onConnectedClientsChanged(SoftApInfo info, List<WifiClient> clients) { + ArrayList<MacAddress> macAddresses = new ArrayList<>(); + clients.forEach(x -> macAddresses.add(x.getMacAddress())); + Bundle msg = new Bundle(); + msg.putParcelable("Info", info); + msg.putParcelableArrayList("ClientsMacAddress", macAddresses); + mEventFacade.postEvent(mEventStr + "OnConnectedClientsChangedWithInfo", msg); + } + + @Override public void onInfoChanged(SoftApInfo softApInfo) { mEventFacade.postEvent(mEventStr + "OnInfoChanged", softApInfo); } @Override + public void onInfoChanged(List<SoftApInfo> infos) { + mEventFacade.postEvent(mEventStr + "OnInfoListChanged", infos); + } + + @Override public void onCapabilityChanged(SoftApCapability softApCapability) { mEventFacade.postEvent(mEventStr + "OnCapabilityChanged", softApCapability); } @@ -280,6 +289,31 @@ public class WifiManagerFacade extends RpcReceiver { } }; + private static class CoexCallbackImpl extends WifiManager.CoexCallback { + private final EventFacade mEventFacade; + private final String mEventStr; + + CoexCallbackImpl(EventFacade eventFacade) { + mEventFacade = eventFacade; + mEventStr = mEventType + "CoexCallback"; + } + + @Override + public void onCoexUnsafeChannelsChanged( + @NonNull List<CoexUnsafeChannel> unsafeChannels, int restrictions) { + Bundle event = new Bundle(); + try { + event.putString("KEY_COEX_UNSAFE_CHANNELS", + coexUnsafeChannelsToJson(unsafeChannels).toString()); + event.putString("KEY_COEX_RESTRICTIONS", + coexRestrictionsToJson(restrictions).toString()); + mEventFacade.postEvent(mEventStr + "#onCoexUnsafeChannelsChanged", event); + } catch (JSONException e) { + Log.e("Failed to post event for onCoexUnsafeChannelsChanged: " + e); + } + } + }; + private WifiLock mLock = null; private boolean mIsConnected = false; @@ -313,6 +347,9 @@ public class WifiManagerFacade extends RpcReceiver { mTrackingNetworkSuggestionStateChange = false; mCallbackHandlerThread.start(); mSoftapCallbacks = new SparseArray<>(); + if (SdkLevel.isAtLeastS()) { + mCoexCallback = new CoexCallbackImpl(mEventFacade); + } } private void makeLock(int wifiMode) { @@ -395,6 +432,53 @@ public class WifiManagerFacade extends RpcReceiver { public class WifiStateChangeReceiver extends BroadcastReceiver { String mCachedWifiInfo = ""; + /** + * When a peer to peer request is active, WifiManager.getConnectionInfo() returns + * the peer to peer connection details. Hence use networking API's to retrieve the + * internet connection details. + * + * But on Android R, we will need to fallback to the legacy getConnectionInfo() API since + * WifiInfo doesn't implement TransportInfo. + */ + private WifiInfo getInternetConnectivityWifiInfo() { + if (!SdkLevel.isAtLeastS()) { + return mWifi.getConnectionInfo(); + } + // TODO (b/156867433): We need a location sensitive synchronous API proposed + // in aosp/1629501. + final CountDownLatch waitForNetwork = new CountDownLatch(1); + final class AnswerBox { + public WifiInfo wifiInfo; + } + final AnswerBox answerBox = new AnswerBox(); + final NetworkCallback networkCallback = + new NetworkCallback(NetworkCallback.FLAG_INCLUDE_LOCATION_INFO) { + @Override + public void onCapabilitiesChanged(@NonNull Network network, + @NonNull NetworkCapabilities networkCapabilities) { + answerBox.wifiInfo = (WifiInfo) networkCapabilities.getTransportInfo(); + waitForNetwork.countDown(); + } + }; + mCm.registerNetworkCallback( + new NetworkRequest.Builder() + .addTransportType(TRANSPORT_WIFI) + .addCapability(NET_CAPABILITY_INTERNET) + .build(), networkCallback); + try { + if (!waitForNetwork.await(5, TimeUnit.SECONDS)) { + Log.e("Timed out waiting for network to connect"); + return null; + } + return answerBox.wifiInfo; + } catch (InterruptedException e) { + Log.e("Waiting for onAvailable failed", e); + return null; + } finally { + mCm.unregisterNetworkCallback(networkCallback); + } + } + @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); @@ -405,7 +489,12 @@ public class WifiManagerFacade extends RpcReceiver { // If network info is of type wifi, send wifi events. if (nInfo.getType() == ConnectivityManager.TYPE_WIFI) { if (nInfo.getDetailedState().equals(DetailedState.CONNECTED)) { - WifiInfo wInfo = mWifi.getConnectionInfo(); + WifiInfo wInfo = getInternetConnectivityWifiInfo(); + if (wInfo == null) { + Log.e("Failed to get WifiInfo for internet connection. " + + "Not sending wifi network connection event"); + return; + } String bssid = wInfo.getBSSID(); if (bssid != null && !mCachedWifiInfo.equals(wInfo.toString())) { Log.d("WifiNetworkConnected"); @@ -519,28 +608,26 @@ public class WifiManagerFacade extends RpcReceiver { // Check if new security type SAE (WPA3) is present. Default to PSK if (j.has("security")) { if (TextUtils.equals(j.getString("security"), "SAE")) { - config.allowedKeyManagement.set(KeyMgmt.SAE); - config.requirePmf = true; + config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_SAE); } else { - config.allowedKeyManagement.set(KeyMgmt.WPA_PSK); + config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_PSK); } } else { - config.allowedKeyManagement.set(KeyMgmt.WPA_PSK); + config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_PSK); } config.preSharedKey = "\"" + j.getString("password") + "\""; } else if (j.has("preSharedKey")) { - config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK); + config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_PSK); config.preSharedKey = j.getString("preSharedKey"); } else { if (j.has("security")) { if (TextUtils.equals(j.getString("security"), "OWE")) { - config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.OWE); - config.requirePmf = true; + config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_OWE); } else { - config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); + config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_OPEN); } } else { - config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); + config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_OPEN); } } if (j.has("BSSID")) { @@ -557,9 +644,7 @@ public class WifiManagerFacade extends RpcReceiver { } if (j.has("wepKeys")) { // Looks like we only support static WEP. - config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); - config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN); - config.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED); + config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_WEP); JSONArray keys = j.getJSONArray("wepKeys"); String[] wepKeys = new String[keys.length()]; for (int i = 0; i < keys.length(); i++) { @@ -582,7 +667,7 @@ public class WifiManagerFacade extends RpcReceiver { return config; } - private WifiEnterpriseConfig genWifiEnterpriseConfig(JSONObject j) throws JSONException, + private static WifiEnterpriseConfig genWifiEnterpriseConfig(JSONObject j) throws JSONException, GeneralSecurityException { WifiEnterpriseConfig eConfig = new WifiEnterpriseConfig(); if (j.has(WifiEnterpriseConfig.EAP_KEY)) { @@ -605,7 +690,11 @@ public class WifiManagerFacade extends RpcReceiver { Log.v("Client Cert String is " + certStr); Log.v("Client Key String is " + keyStr); X509Certificate cert = strToX509Cert(certStr); - PrivateKey privKey = strToPrivateKey(keyStr); + String certAlgo = "RSA"; + if (j.has("cert_algo")) { + certAlgo = j.getString("cert_algo"); + } + PrivateKey privKey = strToPrivateKey(keyStr, certAlgo); Log.v("Cert is " + cert); Log.v("Private Key is " + privKey); eConfig.setClientKeyEntry(privKey, cert); @@ -649,13 +738,11 @@ public class WifiManagerFacade extends RpcReceiver { return null; } WifiConfiguration config = new WifiConfiguration(); - config.allowedKeyManagement.set(KeyMgmt.WPA_EAP); - config.allowedKeyManagement.set(KeyMgmt.IEEE8021X); + config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP); if (j.has("security")) { if (TextUtils.equals(j.getString("security"), "SUITE_B_192")) { - config.allowedKeyManagement.set(KeyMgmt.SUITE_B_192); - config.requirePmf = true; + config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP_SUITE_B); } } @@ -685,7 +772,10 @@ public class WifiManagerFacade extends RpcReceiver { return config; } - private NetworkSpecifier genWifiNetworkSpecifier(JSONObject j) throws JSONException, + /** + * Generate {@link WifiNetworkSpecifier} from the specified json. + */ + public static NetworkSpecifier genWifiNetworkSpecifier(JSONObject j) throws JSONException, GeneralSecurityException { if (j == null) { return null; @@ -794,6 +884,11 @@ public class WifiManagerFacade extends RpcReceiver { } } } + if (j.has("enhancedMacRandomizationEnabled") + && j.getBoolean("enhancedMacRandomizationEnabled")) { + builder = builder.setMacRandomizationSetting( + WifiNetworkSuggestion.RANDOMIZATION_NON_PERSISTENT); + } return builder.build(); } @@ -837,22 +932,22 @@ public class WifiManagerFacade extends RpcReceiver { return info; } - private byte[] base64StrToBytes(String input) { + private static byte[] base64StrToBytes(String input) { return Base64.decode(input, Base64.DEFAULT); } - private X509Certificate strToX509Cert(String certStr) throws CertificateException { + private static X509Certificate strToX509Cert(String certStr) throws CertificateException { byte[] certBytes = base64StrToBytes(certStr); InputStream certStream = new ByteArrayInputStream(certBytes); CertificateFactory cf = CertificateFactory.getInstance("X509"); return (X509Certificate) cf.generateCertificate(certStream); } - private PrivateKey strToPrivateKey(String key) throws NoSuchAlgorithmException, - InvalidKeySpecException { + private static PrivateKey strToPrivateKey(String key, String algo) + throws NoSuchAlgorithmException, InvalidKeySpecException { byte[] keyBytes = base64StrToBytes(key); PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes); - KeyFactory fact = KeyFactory.getInstance("RSA"); + KeyFactory fact = KeyFactory.getInstance(algo); PrivateKey priv = fact.generatePrivate(keySpec); return priv; } @@ -1083,6 +1178,27 @@ public class WifiManagerFacade extends RpcReceiver { } } + private class SubsystemRestartTrackingCallbackFacade extends SubsystemRestartTrackingCallback { + private final EventFacade mEventFacade; + + SubsystemRestartTrackingCallbackFacade(EventFacade eventFacade) { + super(); + mEventFacade = eventFacade; + } + + @Override + public void onSubsystemRestarting() { + Log.v("onSubsystemRestarting"); + mEventFacade.postEvent("WifiSubsystemRestarting", null); + } + + @Override + public void onSubsystemRestarted() { + Log.v("onSubsystemRestarted"); + mEventFacade.postEvent("WifiSubsystemRestarted", null); + } + } + private OsuProvider buildTestOsuProvider(JSONObject config) { String osuServiceDescription = "Google Passpoint Test Service"; List<Integer> osuMethodList = @@ -1233,6 +1349,41 @@ public class WifiManagerFacade extends RpcReceiver { return mWifi.getConnectionInfo(); } + /** + * Check if wifi network is temporary disabled. + * @param config JSONObject Dictionary of wifi connection parameters. + * @return True if network is disabled temporarily, False if not. + */ + @Rpc(description = "Check if network is temporary disabled") + public boolean wifiIsNetworkTemporaryDisabledForNetwork( + @RpcParameter(name = "config") JSONObject config) + throws JSONException, GeneralSecurityException { + WifiConfiguration wifiConfig; + if (config.has(WifiEnterpriseConfig.EAP_KEY)) { + wifiConfig = genWifiConfigWithEnterpriseConfig(config); + } else { + wifiConfig = genWifiConfig(config); + } + List<WifiConfiguration> wifiConfigList = wifiGetConfiguredNetworks(); + for (WifiConfiguration conf : wifiConfigList) { + if (conf.getSsidAndSecurityTypeString().equals( + wifiConfig.getSsidAndSecurityTypeString())) { + Log.d("Found matching config in the configured networks."); + return conf.getNetworkSelectionStatus().isNetworkTemporaryDisabled(); + } + } + Log.d("Wifi config is not in list of configured wifi networks."); + return false; + } + + /** + * Get wifi standard for wifi connection. + */ + @Rpc(description = "Return connection WiFi standard") + public Integer wifiGetConnectionStandard() { + return mWifi.getConnectionInfo().getWifiStandard(); + } + @Rpc(description = "Returns wifi activity and energy usage info.") public WifiActivityEnergyInfo wifiGetControllerActivityEnergyInfo() { WifiActivityEnergyInfo[] mutable = {null}; @@ -1296,14 +1447,51 @@ public class WifiManagerFacade extends RpcReceiver { return mWifi.isVerboseLoggingEnabled() ? 1 : 0; } + /** + * Query whether or not the device supports concurrency of Station (STA) + multiple access + * points (AP) (where the APs bridged together). + * + * @return true if this device supports concurrency of STA + multiple APs which are bridged + * together, false otherwise. + */ + @Rpc(description = "true if this adapter supports STA + bridged Soft AP concurrency.") + public Boolean wifiIsStaBridgedApConcurrencySupported() { + return mWifi.isStaBridgedApConcurrencySupported(); + } + + /** + * Query whether or not the device supports multiple Access point (AP) which are bridged + * together. + * + * @return true if this device supports concurrency of multiple AP which bridged together, + * false otherwise. + */ + @Rpc(description = "true if this adapter supports bridged Soft AP concurrency.") + public Boolean wifiIsBridgedApConcurrencySupported() { + return mWifi.isBridgedApConcurrencySupported(); + } + @Rpc(description = "true if this adapter supports 5 GHz band.") public Boolean wifiIs5GHzBandSupported() { return mWifi.is5GHzBandSupported(); } - @Rpc(description = "true if this adapter supports multiple simultaneous connections.") - public Boolean wifiIsAdditionalStaSupported() { - return mWifi.isAdditionalStaSupported(); + @Rpc(description = "true if this adapter supports multiple simultaneous connections for" + + "local only use-case.") + public Boolean wifiIsStaConcurrencyForLocalOnlyConnectionsSupported() { + return mWifi.isStaConcurrencyForLocalOnlyConnectionsSupported(); + } + + @Rpc(description = "true if this adapter supports multiple simultaneous connections for mbb " + + "wifi to wifi switching.") + public Boolean wifiIsMakeBeforeBreakWifiSwitchingSupported() { + return mWifi.isMakeBeforeBreakWifiSwitchingSupported(); + } + + @Rpc(description = "true if this adapter supports multiple simultaneous connections for " + + "restricted connection use-case.") + public Boolean wifiIsStaConcurrencyForRestrictedConnectionsSupported() { + return mWifi.isStaConcurrencyForRestrictedConnectionsSupported(); } @Rpc(description = "Return true if WiFi is enabled.") @@ -1413,6 +1601,17 @@ public class WifiManagerFacade extends RpcReceiver { public Boolean wifiIsEnhancedOpenSupported() { return mWifi.isEnhancedOpenSupported(); } + + /** + * @return true if this device supports Wi-Fi Device Provisioning Protocol (Easy-connect) + * Enrollee Responder mode + */ + @Rpc(description = "Check if Easy Connect (DPP) Enrollee responder mode is supported " + + "on this device.") + public Boolean wifiIsEasyConnectEnrolleeResponderModeSupported() { + return mWifi.isEasyConnectEnrolleeResponderModeSupported(); + } + /** * @return true if this device supports Wi-Fi Device Provisioning Protocol (Easy-connect) */ @@ -1431,6 +1630,16 @@ public class WifiManagerFacade extends RpcReceiver { makeLock(WifiManager.WIFI_MODE_SCAN_ONLY); } + @Rpc(description = "Acquires a high performance Wifi lock.") + public void wifiLockAcquireFullHighPerf() { + makeLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF); + } + + @Rpc(description = "Acquires a low latency Wifi lock.") + public void wifiLockAcquireFullLowLatency() { + makeLock(WifiManager.WIFI_MODE_FULL_LOW_LATENCY); + } + @Rpc(description = "Releases a previously acquired Wifi lock.") public void wifiLockRelease() { if (mLock != null) { @@ -1454,6 +1663,30 @@ public class WifiManagerFacade extends RpcReceiver { return mWifi.removeNetwork(netId); } + private int getApBandFromChannelFrequency(int freq) { + if (ScanResult.is24GHz(freq)) { + return SoftApConfiguration.BAND_2GHZ; + } else if (ScanResult.is5GHz(freq)) { + return SoftApConfiguration.BAND_5GHZ; + } else if (ScanResult.is6GHz(freq)) { + return SoftApConfiguration.BAND_6GHZ; + } else if (ScanResult.is60GHz(freq)) { + return SoftApConfiguration.BAND_60GHZ; + } + return -1; + } + + private int[] convertJSONArrayToIntArray(JSONArray jArray) throws JSONException { + if (jArray == null) { + return null; + } + int[] iArray = new int[jArray.length()]; + for (int i = 0; i < jArray.length(); i++) { + iArray[i] = jArray.getInt(i); + } + return iArray; + } + private SoftApConfiguration createSoftApConfiguration(JSONObject configJson) throws JSONException { if (configJson == null) { @@ -1524,10 +1757,48 @@ public class WifiManagerFacade extends RpcReceiver { for (int j = 0; j < blockedList.length(); j++) { blockedClientList.add(MacAddress.fromString(blockedList.getString(j))); } - } + configBuilder.setAllowedClientList(allowedClientList); configBuilder.setBlockedClientList(blockedClientList); + + if (SdkLevel.isAtLeastS()) { + if (configJson.has("apBands")) { + JSONArray jBands = configJson.getJSONArray("apBands"); + int[] bands = convertJSONArrayToIntArray(jBands); + configBuilder.setBands(bands); + } + + if (configJson.has("apChannelFrequencies")) { + JSONArray jChannelFrequencys = configJson.getJSONArray("apChannelFrequencies"); + int[] channelFrequencies = convertJSONArrayToIntArray(jChannelFrequencys); + SparseIntArray channels = new SparseIntArray(); + for (int channelFrequency : channelFrequencies) { + if (channelFrequency != 0) { + channels.put(getApBandFromChannelFrequency(channelFrequency), + ScanResult.convertFrequencyMhzToChannelIfSupported( + channelFrequency)); + } + } + if (channels.size() != 0) { + configBuilder.setChannels(channels); + } + } + + if (configJson.has("MacRandomizationSetting")) { + configBuilder.setMacRandomizationSetting( + configJson.getInt("MacRandomizationSetting")); + } + + if (configJson.has("BridgedModeOpportunisticShutdownEnabled")) { + configBuilder.setBridgedModeOpportunisticShutdownEnabled( + configJson.getBoolean("BridgedModeOpportunisticShutdownEnabled")); + } + + if (configJson.has("Ieee80211axEnabled")) { + configBuilder.setIeee80211axEnabled(configJson.getBoolean("Ieee80211axEnabled")); + } + } return configBuilder.build(); } @@ -1684,6 +1955,16 @@ public class WifiManagerFacade extends RpcReceiver { return enabled; } + @Rpc(description = "Restart the WiFi subsystem.") + public void restartWifiSubsystem() { + if (mSubsystemRestartTrackingCallback == null) { + // one-time registration if needed + mSubsystemRestartTrackingCallback = new SubsystemRestartTrackingCallbackFacade( + mEventFacade); + } + mWifi.restartWifiSubsystem(); + } + @Rpc(description = "Toggle Wifi scan always available on and off.", returns = "True if Wifi scan is always available.") public Boolean wifiToggleScanAlwaysAvailable( @RpcParameter(name = "enabled") @RpcOptional Boolean enabled) @@ -1699,91 +1980,6 @@ public class WifiManagerFacade extends RpcReceiver { mWifi.allowAutojoinGlobal(enable); } - private void wifiRequestNetworkWithSpecifierInternal(NetworkSpecifier wns, int timeoutInMs) - throws GeneralSecurityException { - NetworkRequest networkRequest = new NetworkRequest.Builder() - .addTransportType(TRANSPORT_WIFI) - .setNetworkSpecifier(wns) - .build(); - NetworkCallback networkCallback = new NetworkCallbackImpl(); - if (timeoutInMs != 0) { - mCm.requestNetwork(networkRequest, networkCallback, - new Handler(mCallbackHandlerThread.getLooper()), timeoutInMs); - } else { - mCm.requestNetwork(networkRequest, networkCallback, - new Handler(mCallbackHandlerThread.getLooper())); - } - // Store the callback for release later. - mNetworkCallbacks.put(wns, networkCallback); - } - - /** - * Initiates a network request {@link NetworkRequest} using {@link WifiNetworkSpecifier}. - * - * @param wifiNetworkSpecifier JSONObject Dictionary of wifi network specifier parameters - * @throws JSONException - * @throws GeneralSecurityException - */ - @Rpc(description = "Initiates a network request using the provided network specifier") - public void wifiRequestNetworkWithSpecifier( - @RpcParameter(name = "wifiNetworkSpecifier") JSONObject wifiNetworkSpecifier) - throws JSONException, GeneralSecurityException { - wifiRequestNetworkWithSpecifierInternal(genWifiNetworkSpecifier(wifiNetworkSpecifier), 0); - } - - /** - * Initiates a network request {@link NetworkRequest} using {@link WifiNetworkSpecifier}. - * - * @param wifiNetworkSpecifier JSONObject Dictionary of wifi network specifier parameters - * @param timeoutInMs Timeout for the request. - * @throws JSONException - * @throws GeneralSecurityException - */ - @Rpc(description = "Initiates a network request using the provided network specifier") - public void wifiRequestNetworkWithSpecifierWithTimeout( - @RpcParameter(name = "wifiNetworkSpecifier") JSONObject wifiNetworkSpecifier, - @RpcParameter(name = "timeout") Integer timeoutInMs) - throws JSONException, GeneralSecurityException { - wifiRequestNetworkWithSpecifierInternal( - genWifiNetworkSpecifier(wifiNetworkSpecifier), timeoutInMs); - } - - /** - * Releases network request using {@link WifiNetworkSpecifier}. - * - * @throws JSONException - * @throws GeneralSecurityException - */ - @Rpc(description = "Releases network request corresponding to the network specifier") - public void wifiReleaseNetwork( - @RpcParameter(name = "wifiNetworkSpecifier") JSONObject wifiNetworkSpecifier) - throws JSONException, GeneralSecurityException { - NetworkSpecifier wns = genWifiNetworkSpecifier(wifiNetworkSpecifier); - NetworkCallback networkCallback = mNetworkCallbacks.remove(wns); - if (networkCallback == null) { - throw new IllegalArgumentException("network callback is null"); - } - mCm.unregisterNetworkCallback(networkCallback); - } - - /** - * Releases all pending network requests. - * - * @throws JSONException - * @throws GeneralSecurityException - */ - @Rpc(description = "Releases all pending network requests") - public void wifiReleaseNetworkAll() { - Iterator<Map.Entry<NetworkSpecifier, NetworkCallback>> it = - mNetworkCallbacks.entrySet().iterator(); - while (it.hasNext()) { - Map.Entry<NetworkSpecifier, NetworkCallback> entry = it.next(); - NetworkCallback networkCallback = entry.getValue(); - it.remove(); - mCm.unregisterNetworkCallback(networkCallback); - } - } - /** * Register network request match callback to simulate the UI flow. * @@ -1874,7 +2070,6 @@ public class WifiManagerFacade extends RpcReceiver { @Override public void shutdown() { - wifiReleaseNetworkAll(); wifiLockRelease(); if (mTrackingWifiStateChange == true) { wifiStopTrackingStateChange(); @@ -1974,6 +2169,36 @@ public class WifiManagerFacade extends RpcReceiver { Log.d("Posting event: onProgress"); mEventFacade.postEvent(EASY_CONNECT_CALLBACK_TAG, msg); } + + @Override + public void onBootstrapUriGenerated(@NonNull Uri dppUri) { + Bundle msg = new Bundle(); + msg.putString("Type", "onBootstrapUriGenerated"); + Log.d("onBootstrapUriGenerated uri: " + dppUri.toString()); + msg.putString("generatedUri", dppUri.toString()); + Log.d("Posting event: onBootstrapUriGenerated"); + mEventFacade.postEvent(EASY_CONNECT_CALLBACK_TAG, msg); + } + } + + private static @WifiManager.EasyConnectCryptographyCurve + int getEasyConnectCryptographyCurve(String curve) { + + switch (curve) { + case "secp384r1": + return WifiManager.EASY_CONNECT_CRYPTOGRAPHY_CURVE_SECP384R1; + case "secp521r1": + return WifiManager.EASY_CONNECT_CRYPTOGRAPHY_CURVE_SECP521R1; + case "brainpoolP256r1": + return WifiManager.EASY_CONNECT_CRYPTOGRAPHY_CURVE_BRAINPOOLP256R1; + case "brainpoolP384r1": + return WifiManager.EASY_CONNECT_CRYPTOGRAPHY_CURVE_BRAINPOOLP384R1; + case "brainpoolP512r1": + return WifiManager.EASY_CONNECT_CRYPTOGRAPHY_CURVE_BRAINPOOLP512R1; + case "prime256v1": + default: + return WifiManager.EASY_CONNECT_CRYPTOGRAPHY_CURVE_PRIME256V1; + } } /** @@ -2017,6 +2242,24 @@ public class WifiManagerFacade extends RpcReceiver { } /** + * Start Easy Connect (DPP) in Responder-Enrollee role: Receive Wi-Fi configuration from a peer + * + * @param deviceInfo The device specific info to attach in the generated URI + * @param cryptographyCurve Elliptic curve cryptography used to generate DPP + * public/private key pair + */ + @Rpc(description = "Easy Connect Responder-Enrollee: Receive Wi-Fi configuration from peer") + public void startEasyConnectAsEnrolleeResponder(@RpcParameter(name = "deviceInfo") String + deviceInfo, @RpcParameter(name = "cryptographyCurve") String cryptographyCurve) { + EasyConnectCallback dppStatusCallback = new EasyConnectCallback(); + + // Start Easy Connect + mWifi.startEasyConnectAsEnrolleeResponder(deviceInfo, + getEasyConnectCryptographyCurve(cryptographyCurve), mService.getMainExecutor(), + dppStatusCallback); + } + + /** * Stop Easy Connect (DPP) session * */ @@ -2043,4 +2286,165 @@ public class WifiManagerFacade extends RpcReceiver { @RpcParameter(name = "enableAutojoin") Boolean enableAutojoin) { mWifi.allowAutojoinPasspoint(fqdn, enableAutojoin); } + + private static CoexUnsafeChannel genCoexUnsafeChannel(JSONObject j) throws JSONException { + if (j == null || !j.has("band") || !j.has("channel")) { + return null; + } + + final int band; + final String jsonBand = j.getString("band"); + if (TextUtils.equals(jsonBand, "24_GHZ")) { + band = WIFI_BAND_24_GHZ; + } else if (TextUtils.equals(jsonBand, "5_GHZ")) { + band = WIFI_BAND_5_GHZ; + } else { + return null; + } + if (j.has("powerCapDbm")) { + return new CoexUnsafeChannel(band, j.getInt("channel"), j.getInt("powerCapDbm")); + } + return new CoexUnsafeChannel(band, j.getInt("channel")); + } + + private static List<CoexUnsafeChannel> genCoexUnsafeChannels( + JSONArray jsonCoexUnsafeChannelsArray) throws JSONException { + if (jsonCoexUnsafeChannelsArray == null) { + return Collections.emptyList(); + } + List<CoexUnsafeChannel> unsafeChannels = new ArrayList<>(); + for (int i = 0; i < jsonCoexUnsafeChannelsArray.length(); i++) { + unsafeChannels.add( + genCoexUnsafeChannel(jsonCoexUnsafeChannelsArray.getJSONObject(i))); + } + return unsafeChannels; + } + + private static int genCoexRestrictions(JSONArray jsonCoexRestrictionArray) + throws JSONException { + if (jsonCoexRestrictionArray == null) { + return 0; + } + int coexRestrictions = 0; + for (int i = 0; i < jsonCoexRestrictionArray.length(); i++) { + final String jsonRestriction = jsonCoexRestrictionArray.getString(i); + if (TextUtils.equals(jsonRestriction, "WIFI_DIRECT")) { + coexRestrictions |= WifiManager.COEX_RESTRICTION_WIFI_DIRECT; + } + if (TextUtils.equals(jsonRestriction, "SOFTAP")) { + coexRestrictions |= WifiManager.COEX_RESTRICTION_SOFTAP; + } + if (TextUtils.equals(jsonRestriction, "WIFI_AWARE")) { + coexRestrictions |= WifiManager.COEX_RESTRICTION_WIFI_AWARE; + } + } + return coexRestrictions; + } + + /** + * Converts a set of {@link CoexUnsafeChannel} to a {@link JSONArray} of {@link JSONObject} of + * format: + * { + * "band": <"24_GHZ" or "5_GHZ"> + * "channel" : <Channel Number> + * (Optional) "powerCapDbm" : <Power Cap in Dbm> + * } + */ + private static JSONArray coexUnsafeChannelsToJson(List<CoexUnsafeChannel> unsafeChannels) + throws JSONException { + final JSONArray jsonCoexUnsafeChannelArray = new JSONArray(); + for (CoexUnsafeChannel unsafeChannel : unsafeChannels) { + final String jsonBand; + if (unsafeChannel.getBand() == WIFI_BAND_24_GHZ) { + jsonBand = "24_GHZ"; + } else if (unsafeChannel.getBand() == WIFI_BAND_5_GHZ) { + jsonBand = "5_GHZ"; + } else { + continue; + } + final JSONObject jsonUnsafeChannel = new JSONObject(); + jsonUnsafeChannel.put("band", jsonBand); + jsonUnsafeChannel.put("channel", unsafeChannel.getChannel()); + final int powerCapDbm = unsafeChannel.getPowerCapDbm(); + if (powerCapDbm != CoexUnsafeChannel.POWER_CAP_NONE) { + jsonUnsafeChannel.put("powerCapDbm", powerCapDbm); + } + jsonCoexUnsafeChannelArray.put(jsonUnsafeChannel); + } + return jsonCoexUnsafeChannelArray; + } + + /** + * Converts a coex restriction bitmask {@link WifiManager#getCoexRestrictions()} to a JSON array + * of possible values "WIFI_DIRECT", "SOFTAP", "WIFI_AWARE". + */ + private static JSONArray coexRestrictionsToJson(int coexRestrictions) { + final JSONArray jsonCoexRestrictionArray = new JSONArray(); + if ((coexRestrictions & WifiManager.COEX_RESTRICTION_WIFI_DIRECT) != 0) { + jsonCoexRestrictionArray.put("WIFI_DIRECT"); + } + if ((coexRestrictions & WifiManager.COEX_RESTRICTION_SOFTAP) != 0) { + jsonCoexRestrictionArray.put("SOFTAP"); + } + if ((coexRestrictions & WifiManager.COEX_RESTRICTION_WIFI_AWARE) != 0) { + jsonCoexRestrictionArray.put("WIFI_AWARE"); + } + return jsonCoexRestrictionArray; + } + + /** + * Returns whether the default coex algorithm is enabled or not + * + * @return {@code true} if the default coex algorithm is enabled, {@code false} otherwise. + */ + @Rpc(description = "Returns whether the default coex algorithm is enabled or not") + public boolean wifiIsDefaultCoexAlgorithmEnabled() { + if (!SdkLevel.isAtLeastS()) { + return false; + } + return mWifi.isDefaultCoexAlgorithmEnabled(); + } + + /** + * Sets the active list of unsafe channels to avoid for coex and the restricted Wifi interfaces. + * + * @param unsafeChannels JSONArray representation of {@link CoexUnsafeChannel}. + * See {@link #coexUnsafeChannelsToJson(List)}. + * @param restrictions JSONArray representation of coex restrictions. + * See {@link #coexRestrictionsToJson(int)}. + * @throws JSONException + */ + @Rpc(description = "Set the unsafe channels to avoid for coex") + public void wifiSetCoexUnsafeChannels( + @RpcParameter(name = "unsafeChannels") JSONArray unsafeChannels, + @RpcParameter(name = "restrictions") JSONArray restrictions) throws JSONException { + if (!SdkLevel.isAtLeastS()) { + return; + } + mWifi.setCoexUnsafeChannels( + genCoexUnsafeChannels(unsafeChannels), genCoexRestrictions(restrictions)); + } + + /** + * Registers a coex callback to start receiving coex update events. + */ + @Rpc(description = "Registers a coex callback to start receiving coex update events") + public void wifiRegisterCoexCallback() { + if (!SdkLevel.isAtLeastS()) { + return; + } + mWifi.registerCoexCallback( + new HandlerExecutor(mCallbackHandlerThread.getThreadHandler()), mCoexCallback); + } + + /** + * Unregisters the coex callback to stop receiving coex update events. + */ + @Rpc(description = "Unregisters the coex callback to stop receiving coex update events") + public void wifiUnregisterCoexCallback() { + if (!SdkLevel.isAtLeastS()) { + return; + } + mWifi.unregisterCoexCallback(mCoexCallback); + } } diff --git a/Common/src/com/googlecode/android_scripting/facade/wifi/WifiRtt2ManagerFacade.java b/Common/src/com/googlecode/android_scripting/facade/wifi/WifiRtt2ManagerFacade.java index 5197896a..7c1cc008 100644 --- a/Common/src/com/googlecode/android_scripting/facade/wifi/WifiRtt2ManagerFacade.java +++ b/Common/src/com/googlecode/android_scripting/facade/wifi/WifiRtt2ManagerFacade.java @@ -79,7 +79,7 @@ public class WifiRtt2ManagerFacade extends RpcReceiver { @Override public void shutdown() { - // empty + mService.unregisterReceiver(mStateChangedReceiver); } @Rpc(description = "Does the device support the Wi-Fi RTT feature?") diff --git a/Common/src/com/googlecode/android_scripting/jsonrpc/JsonBuilder.java b/Common/src/com/googlecode/android_scripting/jsonrpc/JsonBuilder.java index a06adbcb..739028ca 100644 --- a/Common/src/com/googlecode/android_scripting/jsonrpc/JsonBuilder.java +++ b/Common/src/com/googlecode/android_scripting/jsonrpc/JsonBuilder.java @@ -36,6 +36,7 @@ import android.net.IpPrefix; import android.net.LinkAddress; import android.net.LinkProperties; import android.net.Network; +import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.net.ProxyInfo; import android.net.RouteInfo; @@ -49,8 +50,10 @@ import android.net.wifi.WifiClient; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiEnterpriseConfig; import android.net.wifi.WifiInfo; +import android.net.wifi.WifiScanner; import android.net.wifi.WifiScanner.ScanData; import android.net.wifi.WpsInfo; +import android.net.wifi.aware.WifiAwareNetworkInfo; import android.net.wifi.p2p.WifiP2pConfig; import android.net.wifi.p2p.WifiP2pDevice; import android.net.wifi.p2p.WifiP2pGroup; @@ -83,7 +86,6 @@ import android.telephony.CellSignalStrengthLte; import android.telephony.CellSignalStrengthTdscdma; import android.telephony.CellSignalStrengthWcdma; import android.telephony.ModemActivityInfo; -import android.telephony.ModemActivityInfo.TransmitPower; import android.telephony.NeighboringCellInfo; import android.telephony.ServiceState; import android.telephony.SignalStrength; @@ -94,12 +96,15 @@ import android.telephony.gsm.GsmCellLocation; import android.util.Base64; import android.util.DisplayMetrics; import android.util.SparseArray; +import android.util.SparseIntArray; import com.android.internal.net.LegacyVpnInfo; +import com.android.modules.utils.build.SdkLevel; import com.googlecode.android_scripting.ConvertUtils; import com.googlecode.android_scripting.Log; import com.googlecode.android_scripting.event.Event; +import com.googlecode.android_scripting.facade.ConnectivityConstants; import com.googlecode.android_scripting.facade.DataUsageController.DataUsageInfo; import com.googlecode.android_scripting.facade.telephony.InCallServiceImpl; import com.googlecode.android_scripting.facade.telephony.TelephonyConstants; @@ -124,6 +129,8 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.IntStream; public class JsonBuilder { @@ -238,6 +245,9 @@ public class JsonBuilder { if (data instanceof Network) { return buildNetwork((Network) data); } + if (data instanceof NetworkCapabilities) { + return buildNetworkCapabilities((NetworkCapabilities) data); + } if (data instanceof NetworkInfo) { return buildNetworkInfo((NetworkInfo) data); } @@ -924,10 +934,52 @@ public class JsonBuilder { private static Object buildNetwork(Network data) throws JSONException { JSONObject nw = new JSONObject(); - nw.put("netId", data.netId); + nw.put("netId", data.getNetId()); return nw; } + public static JSONObject buildNetworkCapabilities(JSONObject nc, NetworkCapabilities data) + throws JSONException { + nc.put(ConnectivityConstants.NetworkCallbackContainer.RSSI, + data.getSignalStrength()); + nc.put(ConnectivityConstants.NetworkCallbackContainer.METERED, + !data.hasCapability(ConnectivityConstants.NET_CAPABILITY_TEMPORARILY_NOT_METERED)); + nc.put(ConnectivityConstants.NET_CAPABILITIES_TRANSPORT_TYPE, + new JSONArray(data.getTransportTypes())); + nc.put(ConnectivityConstants.NET_CAPABILITIES_CAPABILITIES, + new JSONArray(data.getCapabilities())); + + if (data.getNetworkSpecifier() != null) { + nc.put("network_specifier", + data.getNetworkSpecifier().toString()); + } + if (data.getTransportInfo() != null) { + nc.put("transport_info", + JsonBuilder.build(data.getTransportInfo())); + if (data.getTransportInfo() instanceof WifiAwareNetworkInfo) { + WifiAwareNetworkInfo anc = + (WifiAwareNetworkInfo) data.getTransportInfo(); + + String ipv6 = anc.getPeerIpv6Addr().toString(); + if (ipv6.charAt(0) == '/') { + ipv6 = ipv6.substring(1); + } + nc.put("aware_ipv6", ipv6); + if (anc.getPort() != 0) { + nc.put("aware_port", anc.getPort()); + } + if (anc.getTransportProtocol() != -1) { + nc.put("aware_transport_protocol", anc.getTransportProtocol()); + } + } + } + return nc; + } + + private static Object buildNetworkCapabilities(NetworkCapabilities data) throws JSONException { + return buildNetworkCapabilities(new JSONObject(), data); + } + private static Object buildNetworkInfo(NetworkInfo data) throws JSONException { JSONObject info = new JSONObject(); @@ -1056,6 +1108,22 @@ public class JsonBuilder { return result; } + private static @WifiScanner.WifiBand int apBand2wifiScannerBand( + @SoftApConfiguration.BandType int band) { + switch(band) { + case SoftApConfiguration.BAND_2GHZ: + return WifiScanner.WIFI_BAND_24_GHZ; + case SoftApConfiguration.BAND_5GHZ: + return WifiScanner.WIFI_BAND_5_GHZ; + case SoftApConfiguration.BAND_6GHZ: + return WifiScanner.WIFI_BAND_6_GHZ; + case SoftApConfiguration.BAND_60GHZ: + return WifiScanner.WIFI_BAND_60_GHZ; + default: + return WifiScanner.WIFI_BAND_UNSPECIFIED; + } + } + private static Object buildSoftApConfiguration(SoftApConfiguration data) throws JSONException { JSONObject config = new JSONObject(); @@ -1083,6 +1151,26 @@ public class JsonBuilder { config.put("ClientControlByUserEnabled", data.isClientControlByUserEnabled()); config.put("AllowedClientList", build(data.getAllowedClientList())); config.put("BlockedClientList", build(data.getBlockedClientList())); + if (SdkLevel.isAtLeastS()) { + config.put("apBands", buildJSONArray( + IntStream.of(data.getBands()).boxed().toArray(Integer[]::new))); + SparseIntArray channels = data.getChannels(); + int[] channelFrequencies = new int[channels.size()]; + for (int i = 0; i < channels.size(); i++) { + int channel = channels.valueAt(i); + channelFrequencies[i] = channel == 0 ? 0 + : ScanResult.convertChannelToFrequencyMhzIfSupported( + channel, apBand2wifiScannerBand(channels.keyAt(i))); + } + if (channelFrequencies.length != 0) { + config.put("apChannelFrequencies", build( + IntStream.of(channelFrequencies).boxed().toArray(Integer[]::new))); + } + config.put("MacRandomizationSetting", build(data.getMacRandomizationSetting())); + config.put("BridgedModeOpportunisticShutdownEnabled", + build(data.isBridgedModeOpportunisticShutdownEnabled())); + config.put("Ieee80211axEnabled", build(data.isIeee80211axEnabled())); + } return config; } @@ -1221,6 +1309,29 @@ public class JsonBuilder { SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT)); info.put("wpa3SaeSupported", data.areFeaturesSupported( SoftApCapability.SOFTAP_FEATURE_WPA3_SAE)); + info.put("ieee80211axSupported", data.areFeaturesSupported( + SoftApCapability.SOFTAP_FEATURE_IEEE80211_AX)); + info.put("24gSupported", data.areFeaturesSupported( + SoftApCapability.SOFTAP_FEATURE_BAND_24G_SUPPORTED)); + info.put("5gSupported", data.areFeaturesSupported( + SoftApCapability.SOFTAP_FEATURE_BAND_5G_SUPPORTED)); + info.put("6gSupported", data.areFeaturesSupported( + SoftApCapability.SOFTAP_FEATURE_BAND_6G_SUPPORTED)); + info.put("60gSupported", data.areFeaturesSupported( + SoftApCapability.SOFTAP_FEATURE_BAND_60G_SUPPORTED)); + info.put("supported2GHzChannellist", build( + IntStream.of(data.getSupportedChannelList(SoftApConfiguration.BAND_2GHZ)) + .boxed().toArray(Integer[]::new))); + + info.put("supported5GHzChannellist", build( + IntStream.of(data.getSupportedChannelList(SoftApConfiguration.BAND_5GHZ)) + .boxed().toArray(Integer[]::new))); + info.put("supported6GHzChannellist", build( + IntStream.of(data.getSupportedChannelList(SoftApConfiguration.BAND_6GHZ)) + .boxed().toArray(Integer[]::new))); + info.put("supported60GHzChannellist", build( + IntStream.of(data.getSupportedChannelList(SoftApConfiguration.BAND_60GHZ)) + .boxed().toArray(Integer[]::new))); return info; } @@ -1230,6 +1341,11 @@ public class JsonBuilder { Log.d("build softAp info."); info.put("frequency", data.getFrequency()); info.put("bandwidth", data.getBandwidth()); + info.put("autoShutdownTimeoutMillis", data.getAutoShutdownTimeoutMillis()); + if (SdkLevel.isAtLeastS()) { + info.put("wifiStandard", data.getWifiStandard()); + info.put("bssid", data.getBssid()); + } return info; } @@ -1410,16 +1526,14 @@ public class JsonBuilder { throws JSONException { JSONObject info = new JSONObject(); - info.put("Timestamp", modemInfo.getTimestamp()); + info.put("Timestamp", modemInfo.getTimestampMillis()); info.put("SleepTimeMs", modemInfo.getSleepTimeMillis()); info.put("IdleTimeMs", modemInfo.getIdleTimeMillis()); - // convert from int[] to List<Integer> for proper JSON translation - List<TransmitPower> txPowerIno = modemInfo.getTransmitPowerInfo(); - List<Integer> tmp = new ArrayList<Integer>(txPowerIno.size()); - for (TransmitPower val : txPowerIno) { - tmp.add(val.getTimeInMillis()); - } - info.put("TxTimeMs", build(tmp)); + List<Long> txPowerDurations = IntStream.range(0, 5) + .mapToLong(modemInfo::getTransmitDurationMillisAtPowerLevel) + .boxed() + .collect(Collectors.toList()); + info.put("TxTimeMs", build(txPowerDurations)); info.put("RxTimeMs", modemInfo.getReceiveTimeMillis()); return info; } @@ -1538,7 +1652,7 @@ public class JsonBuilder { info.put(TelephonyConstants.ServiceStateContainer.IS_USING_CARRIER_AGGREGATION, ss.isUsingCarrierAggregation()); info.put(TelephonyConstants.ServiceStateContainer.LTE_EARFCN_RSRP_BOOST, - ss.getLteEarfcnRsrpBoost()); + ss.getArfcnRsrpBoost()); return info; } diff --git a/Common/src/com/googlecode/android_scripting/rpc/MethodDescriptor.java b/Common/src/com/googlecode/android_scripting/rpc/MethodDescriptor.java index f1a86343..14165748 100644 --- a/Common/src/com/googlecode/android_scripting/rpc/MethodDescriptor.java +++ b/Common/src/com/googlecode/android_scripting/rpc/MethodDescriptor.java @@ -26,10 +26,6 @@ import com.googlecode.android_scripting.jsonrpc.RpcReceiver; import com.googlecode.android_scripting.jsonrpc.RpcReceiverManager; import com.googlecode.android_scripting.util.VisibleForTesting; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.lang.reflect.Method; @@ -41,6 +37,10 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + /** * An adapter that wraps {@code Method}. */ diff --git a/InterpreterForAndroid/Android.bp b/InterpreterForAndroid/Android.bp index 452b65d8..1a963b83 100644 --- a/InterpreterForAndroid/Android.bp +++ b/InterpreterForAndroid/Android.bp @@ -14,6 +14,15 @@ // limitations under the License. // +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "external_sl4a_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["external_sl4a_license"], +} + java_library { name: "sl4a.InterpreterForAndroid", owner: "google", diff --git a/METADATA b/METADATA new file mode 100644 index 00000000..6d8601bb --- /dev/null +++ b/METADATA @@ -0,0 +1,3 @@ +third_party { + license_type: RESTRICTED +} diff --git a/ScriptingLayer/Android.bp b/ScriptingLayer/Android.bp index cf65c2e8..c2967554 100644 --- a/ScriptingLayer/Android.bp +++ b/ScriptingLayer/Android.bp @@ -14,6 +14,15 @@ // limitations under the License. // +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "external_sl4a_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["external_sl4a_license"], +} + java_library { name: "sl4a.ScriptingLayer", owner: "google", diff --git a/ScriptingLayerForAndroid/Android.bp b/ScriptingLayerForAndroid/Android.bp index bfe27c92..46797e76 100644 --- a/ScriptingLayerForAndroid/Android.bp +++ b/ScriptingLayerForAndroid/Android.bp @@ -14,6 +14,16 @@ // limitations under the License. // +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "external_sl4a_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + // SPDX-license-identifier-GPL-2.0 + default_applicable_licenses: ["external_sl4a_license"], +} + android_test_helper_app { name: "sl4a", @@ -56,6 +66,9 @@ android_test_helper_app { }, jni_libs: ["libcom_googlecode_android_scripting_Exec"], + + min_sdk_version: "30", + target_sdk_version: "31", } java_import { diff --git a/ScriptingLayerForAndroid/AndroidManifest.xml b/ScriptingLayerForAndroid/AndroidManifest.xml index 11db7879..441342ce 100644 --- a/ScriptingLayerForAndroid/AndroidManifest.xml +++ b/ScriptingLayerForAndroid/AndroidManifest.xml @@ -117,14 +117,14 @@ <uses-permission android:name="android.permission.WRITE_USER_DICTIONARY" /> <uses-permission android:name="com.android.certinstaller.INSTALL_AS_USER" /> <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" /> - <uses-permission android:name="com.android.permission.WHITELIST_BLUETOOTH_DEVICE" /> + <uses-permission android:name="com.android.permission.ALLOWLIST_BLUETOOTH_DEVICE" /> <application android:icon="@drawable/sl4a_logo_48" android:label="@string/application_title" android:name=".Sl4aApplication" android:theme="@android:style/Theme.DeviceDefault" android:usesCleartextTraffic="true"> - <activity android:name=".activity.ScriptManager" android:configChanges="keyboardHidden|orientation" android:windowSoftInputMode="adjustResize" android:launchMode="singleTop"> + <activity android:name=".activity.ScriptManager" android:configChanges="keyboardHidden|orientation" android:windowSoftInputMode="adjustResize" android:launchMode="singleTop" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> @@ -134,7 +134,7 @@ </intent-filter> <meta-data android:name="android.app.searchable" android:resource="@xml/searchable_scripts" /> </activity> - <activity android:name=".activity.ScriptPicker" android:configChanges="keyboardHidden|orientation" android:label="Scripts"> + <activity android:name=".activity.ScriptPicker" android:configChanges="keyboardHidden|orientation" android:label="Scripts" android:exported="true"> <intent-filter> <action android:name="android.intent.action.CREATE_SHORTCUT" /> <category android:name="android.intent.category.DEFAULT" /> @@ -145,31 +145,36 @@ <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> - <activity android:name=".activity.InterpreterPicker" android:configChanges="keyboardHidden|orientation" android:label="Interpreters"> + <activity android:name=".activity.InterpreterPicker" android:configChanges="keyboardHidden|orientation" android:label="Interpreters" + android:exported="true"> <intent-filter> <action android:name="android.intent.action.CREATE_SHORTCUT" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> - <activity-alias android:name="LocalePlugin" android:targetActivity=".activity.ScriptPicker" android:label="@string/application_title" android:icon="@drawable/sl4a_logo_32"> + <activity-alias android:name="LocalePlugin" android:targetActivity=".activity.ScriptPicker" android:label="@string/application_title" android:icon="@drawable/sl4a_logo_32" + android:exported="true"> <intent-filter> <action android:name="com.twofortyfouram.locale.intent.action.EDIT_SETTING" /> </intent-filter> </activity-alias> - <receiver android:name=".locale.LocaleReceiver"> + <receiver android:name=".locale.LocaleReceiver" + android:exported="true"> <intent-filter> <action android:name="com.twofortyfouram.locale.intent.action.FIRE_SETTING" /> </intent-filter> </receiver> <activity android:name=".activity.Preferences" android:theme="@android:style/Theme.DeviceDefault.Settings" /> <activity android:name="org.connectbot.ConsoleActivity" android:theme="@android:style/Theme.DeviceDefault.NoActionBar" android:configChanges="keyboardHidden|orientation" android:windowSoftInputMode="stateAlwaysVisible|adjustResize" android:finishOnTaskLaunch="true" android:launchMode="singleTask" /> - <activity android:name=".activity.ScriptEditor" android:theme="@android:style/Theme.DeviceDefault.NoActionBar" android:configChanges="keyboardHidden|orientation" android:windowSoftInputMode="stateAlwaysVisible|adjustResize"> + <activity android:name=".activity.ScriptEditor" android:theme="@android:style/Theme.DeviceDefault.NoActionBar" android:configChanges="keyboardHidden|orientation" android:windowSoftInputMode="stateAlwaysVisible|adjustResize" + android:exported="true"> <intent-filter> <action android:name="com.googlecode.android_scripting.action.EDIT_SCRIPT" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> - <activity android:name=".activity.ApiBrowser" android:configChanges="keyboardHidden|orientation" android:launchMode="singleTop" android:windowSoftInputMode="adjustResize"> + <activity android:name=".activity.ApiBrowser" android:configChanges="keyboardHidden|orientation" android:launchMode="singleTop" android:windowSoftInputMode="adjustResize" + android:exported="true"> <intent-filter> <action android:name="android.intent.action.SEARCH" /> </intent-filter> @@ -178,7 +183,8 @@ <activity android:name=".activity.ApiPrompt" android:theme="@android:style/Theme.DeviceDefault.NoActionBar" android:configChanges="keyboardHidden|orientation" /> <activity android:name=".activity.TriggerManager" android:launchMode="singleTask" android:configChanges="keyboardHidden|orientation" /> <activity android:name=".activity.BluetoothDeviceList" android:configChanges="keyboardHidden|orientation" /> - <activity android:name=".activity.ScriptingLayerServiceLauncher" android:taskAffinity="" android:theme="@android:style/Theme.DeviceDefault.NoActionBar.TranslucentDecor"> + <activity android:name=".activity.ScriptingLayerServiceLauncher" android:taskAffinity="" android:theme="@android:style/Theme.DeviceDefault.NoActionBar.TranslucentDecor" + android:exported="true"> <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> @@ -190,7 +196,8 @@ <service android:name=".service.ScriptingLayerService" /> <service android:name=".service.TriggerService" /> <service android:name="com.googlecode.android_scripting.facade.telephony.InCallServiceImpl" - android:permission="android.permission.BIND_INCALL_SERVICE" > + android:permission="android.permission.BIND_INCALL_SERVICE" + android:exported="true"> <intent-filter> <action android:name="android.telecom.InCallService"/> </intent-filter> @@ -202,14 +209,16 @@ <action android:name="com.googlecode.android_scripting.service.FacadeService.ACTION_BIND" /> </intent-filter> </service> - <service android:name=".facade.bluetooth.media.BluetoothSL4AAudioSrcMBS"> + <service android:name=".facade.bluetooth.media.BluetoothSL4AAudioSrcMBS" + android:exported="true"> <intent-filter> <action android:name="android.media.browse.MediaBrowserService"/> </intent-filter> </service> <activity android:name=".activity.InterpreterManager" android:launchMode="singleTask" android:configChanges="keyboardHidden|orientation" /> <activity android:name=".activity.LogcatViewer" android:launchMode="singleTask" android:configChanges="keyboardHidden|orientation" /> - <activity android:name=".activity.ScriptsLiveFolder" android:label="Scripts" android:icon="@drawable/live_folder" android:configChanges="keyboardHidden|orientation"> + <activity android:name=".activity.ScriptsLiveFolder" android:label="Scripts" android:icon="@drawable/live_folder" android:configChanges="keyboardHidden|orientation" + android:exported="true"> <intent-filter> <action android:name="android.intent.action.CREATE_LIVE_FOLDER" /> <category android:name="android.intent.category.DEFAULT" /> @@ -231,7 +240,8 @@ </provider> <uses-library android:name="android.test.runner" /> <activity android:name=".activity.ScriptProcessMonitor" android:launchMode="singleTask" android:finishOnTaskLaunch="true" /> - <activity android:configChanges="keyboardHidden|orientation" android:name="org.connectbot.util.ColorsActivity" android:theme="@android:style/Theme.DeviceDefault.Dialog"> + <activity android:configChanges="keyboardHidden|orientation" android:name="org.connectbot.util.ColorsActivity" android:theme="@android:style/Theme.DeviceDefault.Dialog" + android:exported="true"> <intent-filter> <action android:name="com.googlecode.android_scripting.PICK_TERMINAL_COLORS" /> <category android:name="android.intent.category.DEFAULT" /> diff --git a/ScriptingLayerForAndroid/jni/Android.bp b/ScriptingLayerForAndroid/jni/Android.bp index cb5e991b..d7f6d7aa 100644 --- a/ScriptingLayerForAndroid/jni/Android.bp +++ b/ScriptingLayerForAndroid/jni/Android.bp @@ -14,6 +14,15 @@ // limitations under the License. // +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "external_sl4a_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["external_sl4a_license"], +} + cc_library_shared { name: "libcom_googlecode_android_scripting_Exec", @@ -25,6 +34,8 @@ cc_library_shared { "-Wno-unused-parameter", ], + header_libs: ["jni_headers"], + shared_libs: ["liblog"], sdk_version: "23", diff --git a/ScriptingLayerForAndroid/src/com/googlecode/android_scripting/service/ScriptingLayerService.java b/ScriptingLayerForAndroid/src/com/googlecode/android_scripting/service/ScriptingLayerService.java index eab396d3..9d5b4cf5 100644 --- a/ScriptingLayerForAndroid/src/com/googlecode/android_scripting/service/ScriptingLayerService.java +++ b/ScriptingLayerForAndroid/src/com/googlecode/android_scripting/service/ScriptingLayerService.java @@ -120,7 +120,9 @@ public class ScriptingLayerService extends ForegroundService { protected Notification createNotification() { Intent notificationIntent = new Intent(this, ScriptingLayerService.class); notificationIntent.setAction(Constants.ACTION_SHOW_RUNNING_SCRIPTS); - mNotificationPendingIntent = PendingIntent.getService(this, 0, notificationIntent, 0); + mNotificationPendingIntent = + PendingIntent.getService(this, 0, notificationIntent, + PendingIntent.FLAG_IMMUTABLE); createNotificationChannel(); Notification.Builder builder = new Notification.Builder(this, CHANNEL_ID); diff --git a/ScriptingLayerForAndroid/src/com/googlecode/android_scripting/service/TriggerService.java b/ScriptingLayerForAndroid/src/com/googlecode/android_scripting/service/TriggerService.java index b9115dfc..bf6f235d 100644 --- a/ScriptingLayerForAndroid/src/com/googlecode/android_scripting/service/TriggerService.java +++ b/ScriptingLayerForAndroid/src/com/googlecode/android_scripting/service/TriggerService.java @@ -127,7 +127,8 @@ public class TriggerService extends ForegroundService { .setWhen(System.currentTimeMillis()) .setContentTitle("SL4A Trigger Service") .setContentText("Tap to view triggers") - .setContentIntent(PendingIntent.getActivity(this, 0, notificationIntent, 0)); + .setContentIntent(PendingIntent.getActivity(this, 0, notificationIntent, + PendingIntent.FLAG_IMMUTABLE)); Notification notification = builder.build(); notification.flags = Notification.FLAG_NO_CLEAR | Notification.FLAG_ONGOING_EVENT; return notification; diff --git a/Utils/Android.bp b/Utils/Android.bp index d48d3170..51b13255 100644 --- a/Utils/Android.bp +++ b/Utils/Android.bp @@ -14,6 +14,15 @@ // limitations under the License. // +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "external_sl4a_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["external_sl4a_license"], +} + java_library { name: "sl4a.Utils", owner: "google", diff --git a/Utils/src/com/googlecode/android_scripting/Log.java b/Utils/src/com/googlecode/android_scripting/Log.java index b3ad6c35..775d67ec 100644 --- a/Utils/src/com/googlecode/android_scripting/Log.java +++ b/Utils/src/com/googlecode/android_scripting/Log.java @@ -74,7 +74,8 @@ public class Log { .setWhen(0) .setContentTitle(contentTitle) .setContentText(message) - .setContentIntent(PendingIntent.getService(context, 0, null, 0)); + .setContentIntent(PendingIntent.getService(context, 0, null, + PendingIntent.FLAG_IMMUTABLE)); Notification note = builder.build(); note.contentView.getLayoutId(); notificationManager.notify(NotificationIdFactory.create(), note); |