Prepare CaptivePortalLogin for system_current
Includes small changes to stop using non-SystemApi endpoints.
Test: make CaptivePortalLogin
Test: flashed, login works, SSL certificate invalid flow works
Bug: 112869080
Change-Id: Ic6ce98942959705ea7ef14a7a62d33e3abf7eb72
diff --git a/packages/CaptivePortalLogin/Android.bp b/packages/CaptivePortalLogin/Android.bp
new file mode 100644
index 0000000..b3e4e83
--- /dev/null
+++ b/packages/CaptivePortalLogin/Android.bp
@@ -0,0 +1,27 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+android_app {
+ name: "CaptivePortalLogin",
+ srcs: ["src/**/*.java"],
+ platform_apis: true,
+ certificate: "platform",
+ static_libs: [
+ "androidx.legacy_legacy-support-v4",
+ "metrics-constants-protos",
+ ],
+ manifest: "AndroidManifest.xml",
+}
diff --git a/packages/CaptivePortalLogin/Android.mk b/packages/CaptivePortalLogin/Android.mk
deleted file mode 100644
index 8c63f45..0000000
--- a/packages/CaptivePortalLogin/Android.mk
+++ /dev/null
@@ -1,14 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-LOCAL_USE_AAPT2 := true
-LOCAL_STATIC_ANDROID_LIBRARIES := androidx.legacy_legacy-support-v4
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CaptivePortalLogin
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_CERTIFICATE := platform
-
-include $(BUILD_PACKAGE)
diff --git a/packages/CaptivePortalLogin/AndroidManifest.xml b/packages/CaptivePortalLogin/AndroidManifest.xml
index 5ab6632..e15dca0 100644
--- a/packages/CaptivePortalLogin/AndroidManifest.xml
+++ b/packages/CaptivePortalLogin/AndroidManifest.xml
@@ -21,9 +21,10 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
- <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
- <uses-permission android:name="android.permission.NETWORK_BYPASS_PRIVATE_DNS" />
+ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.NETWORK_SETTINGS" />
+ <uses-permission android:name="android.permission.NETWORK_BYPASS_PRIVATE_DNS" />
<application android:label="@string/app_name"
android:usesCleartextTraffic="true"
diff --git a/packages/CaptivePortalLogin/res/layout/ssl_error_msg.xml b/packages/CaptivePortalLogin/res/layout/ssl_error_msg.xml
deleted file mode 100644
index d460041..0000000
--- a/packages/CaptivePortalLogin/res/layout/ssl_error_msg.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 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.
--->
-
-<TextView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/ssl_error_msg"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:layout_marginStart="20dip"
- android:layout_marginEnd="20dip"
- android:gravity="center_vertical"
- android:layout_marginBottom="4dip"
- android:layout_marginTop="4dip" />
-
diff --git a/packages/CaptivePortalLogin/res/layout/ssl_warning.xml b/packages/CaptivePortalLogin/res/layout/ssl_warning.xml
index ffd57a4..ce05e78 100644
--- a/packages/CaptivePortalLogin/res/layout/ssl_warning.xml
+++ b/packages/CaptivePortalLogin/res/layout/ssl_warning.xml
@@ -78,7 +78,18 @@
android:id="@+id/certificate_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:orientation="vertical"
android:layout_marginBottom="16dip" >
+ <TextView
+ android:id="@+id/ssl_error_msg"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:layout_marginStart="20dip"
+ android:layout_marginEnd="20dip"
+ android:gravity="center_vertical"
+ android:layout_marginBottom="4dip"
+ android:layout_marginTop="16dip" />
</LinearLayout>
</ScrollView>
diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
index 0a571c5..ce627ce 100644
--- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
+++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
@@ -20,7 +20,7 @@
import android.app.Activity;
import android.app.AlertDialog;
-import android.app.LoadedApk;
+import android.app.Application;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
@@ -37,8 +37,9 @@
import android.net.http.SslCertificate;
import android.net.http.SslError;
import android.net.wifi.WifiInfo;
-import android.os.Build;
+import android.net.wifi.WifiManager;
import android.os.Bundle;
+import android.os.SystemProperties;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
@@ -96,6 +97,7 @@
private CaptivePortal mCaptivePortal;
private NetworkCallback mNetworkCallback;
private ConnectivityManager mCm;
+ private WifiManager mWifiManager;
private boolean mLaunchBrowser = false;
private MyWebViewClient mWebViewClient;
private SwipeRefreshLayout mSwipeRefreshLayout;
@@ -109,7 +111,8 @@
mCaptivePortal = getIntent().getParcelableExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL);
logMetricsEvent(MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_ACTIVITY);
- mCm = ConnectivityManager.from(this);
+ mCm = getSystemService(ConnectivityManager.class);
+ mWifiManager = getSystemService(WifiManager.class);
mNetwork = getIntent().getParcelableExtra(ConnectivityManager.EXTRA_NETWORK);
mUserAgent =
getIntent().getStringExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_USER_AGENT);
@@ -151,7 +154,6 @@
// Also initializes proxy system properties.
mNetwork = mNetwork.getPrivateDnsBypassingCopy();
mCm.bindProcessToNetwork(mNetwork);
- mCm.setProcessDefaultNetworkForHostResolution(mNetwork);
// Proxy system properties must be initialized before setContentView is called because
// setContentView initializes the WebView logic which in turn reads the system properties.
@@ -190,9 +192,12 @@
// Find WebView's proxy BroadcastReceiver and prompt it to read proxy system properties.
private void setWebViewProxy() {
- LoadedApk loadedApk = getApplication().mLoadedApk;
+ // TODO: migrate to androidx WebView proxy setting API as soon as it is finalized
try {
- Field receiversField = LoadedApk.class.getDeclaredField("mReceivers");
+ final Field loadedApkField = Application.class.getDeclaredField("mLoadedApk");
+ final Class<?> loadedApkClass = loadedApkField.getType();
+ final Object loadedApk = loadedApkField.get(getApplication());
+ Field receiversField = loadedApkClass.getDeclaredField("mReceivers");
receiversField.setAccessible(true);
ArrayMap receivers = (ArrayMap) receiversField.get(loadedApk);
for (Object receiverMap : receivers.values()) {
@@ -333,7 +338,11 @@
private static String sanitizeURL(URL url) {
// In non-Debug build, only show host to avoid leaking private info.
- return Build.IS_DEBUGGABLE ? Objects.toString(url) : host(url);
+ return isDebuggable() ? Objects.toString(url) : host(url);
+ }
+
+ private static boolean isDebuggable() {
+ return SystemProperties.getInt("ro.debuggable", 0) == 1;
}
private void testForCaptivePortal() {
@@ -586,19 +595,18 @@
}
private void setViewSecurityCertificate(LinearLayout certificateLayout, SslError error) {
+ ((TextView) certificateLayout.findViewById(R.id.ssl_error_msg))
+ .setText(sslErrorMessage(error));
SslCertificate cert = error.getCertificate();
-
- View certificateView = cert.inflateCertificateView(CaptivePortalLoginActivity.this);
- final LinearLayout placeholder = (LinearLayout) certificateView
- .findViewById(com.android.internal.R.id.placeholder);
- LayoutInflater factory = LayoutInflater.from(CaptivePortalLoginActivity.this);
-
- TextView textView = (TextView) factory.inflate(
- R.layout.ssl_error_msg, placeholder, false);
- textView.setText(sslErrorMessage(error));
- placeholder.addView(textView);
-
- certificateLayout.addView(certificateView);
+ // TODO: call the method directly once inflateCertificateView is @SystemApi
+ try {
+ final View certificateView = (View) SslCertificate.class.getMethod(
+ "inflateCertificateView", Context.class)
+ .invoke(cert, CaptivePortalLoginActivity.this);
+ certificateLayout.addView(certificateView);
+ } catch (ReflectiveOperationException | SecurityException e) {
+ Log.e(TAG, "Could not create certificate view", e);
+ }
}
}
@@ -619,11 +627,30 @@
private String getHeaderTitle() {
NetworkCapabilities nc = mCm.getNetworkCapabilities(mNetwork);
- if (nc == null || TextUtils.isEmpty(nc.getSSID())
- || !nc.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
+ final String ssid = getSsid();
+ if (TextUtils.isEmpty(ssid)
+ || nc == null || !nc.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
return getString(R.string.action_bar_label);
}
- return getString(R.string.action_bar_title, WifiInfo.removeDoubleQuotes(nc.getSSID()));
+ return getString(R.string.action_bar_title, ssid);
+ }
+
+ // TODO: remove once SSID is obtained from NetworkCapabilities
+ private String getSsid() {
+ if (mWifiManager == null) {
+ return null;
+ }
+ final WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
+ return removeDoubleQuotes(wifiInfo.getSSID());
+ }
+
+ private static String removeDoubleQuotes(String string) {
+ if (string == null) return null;
+ final int length = string.length();
+ if ((length > 1) && (string.charAt(0) == '"') && (string.charAt(length - 1) == '"')) {
+ return string.substring(1, length - 1);
+ }
+ return string;
}
private String getHeaderSubtitle(URL url) {
diff --git a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
index b34efc4..dbffa6d 100644
--- a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
+++ b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
@@ -109,6 +109,8 @@
private static final boolean DBG = true;
private static final boolean VDBG = false;
private static final boolean VDBG_STALL = Log.isLoggable(TAG, Log.DEBUG);
+ // TODO: use another permission for CaptivePortalLoginActivity once it has its own certificate
+ private static final String PERMISSION_NETWORK_SETTINGS = "android.permission.NETWORK_SETTINGS";
// Default configuration values for captive portal detection probes.
// TODO: append a random length parameter to the default HTTPS url.
// TODO: randomize browser version ids in the default User-Agent String.
@@ -682,7 +684,7 @@
public void appResponse(int response) {
if (response == APP_RETURN_WANTED_AS_IS) {
mContext.enforceCallingPermission(
- android.Manifest.permission.CONNECTIVITY_INTERNAL,
+ PERMISSION_NETWORK_SETTINGS,
"CaptivePortal");
}
sendMessage(CMD_CAPTIVE_PORTAL_APP_FINISHED, response);
@@ -692,7 +694,7 @@
public void logEvent(int eventId, String packageName)
throws RemoteException {
mContext.enforceCallingPermission(
- android.Manifest.permission.CONNECTIVITY_INTERNAL,
+ PERMISSION_NETWORK_SETTINGS,
"CaptivePortal");
mCallback.logCaptivePortalLoginEvent(eventId, packageName);
}
diff --git a/proto/Android.bp b/proto/Android.bp
index f3811bd..817a54d 100644
--- a/proto/Android.bp
+++ b/proto/Android.bp
@@ -17,3 +17,24 @@
},
},
}
+
+java_library_static {
+ name: "metrics-constants-protos",
+ host_supported: true,
+ proto: {
+ type: "nano",
+ },
+ srcs: ["src/metrics_constants/metrics_constants.proto"],
+ no_framework_libs: true,
+ sdk_version: "system_current",
+ // Pin java_version until jarjar is certified to support later versions. http://b/72703434
+ java_version: "1.8",
+ target: {
+ android: {
+ jarjar_rules: "jarjar-rules.txt",
+ },
+ host: {
+ static_libs: ["libprotobuf-java-nano"],
+ },
+ },
+}