Merge "Prepare CaptivePortalLogin for system_current" am: 74b1c8626e
am: 9b29d62990

Change-Id: Id953d39b834fbe72137fcd7ee3b4aacc92266dbd
diff --git a/packages/CaptivePortalLogin/Android.bp b/packages/CaptivePortalLogin/Android.bp
new file mode 100644
index 0000000..f5e252c
--- /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: [
+        "android-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 7dc23ff..0000000
--- a/packages/CaptivePortalLogin/Android.mk
+++ /dev/null
@@ -1,13 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-LOCAL_STATIC_JAVA_LIBRARIES := android-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 c84f3ec..e15dca0 100644
--- a/packages/CaptivePortalLogin/AndroidManifest.xml
+++ b/packages/CaptivePortalLogin/AndroidManifest.xml
@@ -21,7 +21,8 @@
 
     <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.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" />
 
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 08b22c7..9b70ff3 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.support.v4.widget.SwipeRefreshLayout;
 import android.text.TextUtils;
 import android.util.ArrayMap;
@@ -95,6 +96,7 @@
     private CaptivePortal mCaptivePortal;
     private NetworkCallback mNetworkCallback;
     private ConnectivityManager mCm;
+    private WifiManager mWifiManager;
     private boolean mLaunchBrowser = false;
     private MyWebViewClient mWebViewClient;
     private SwipeRefreshLayout mSwipeRefreshLayout;
@@ -108,7 +110,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);
@@ -150,7 +153,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.
@@ -189,9 +191,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()) {
@@ -332,7 +337,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() {
@@ -585,19 +594,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);
+            }
         }
     }
 
@@ -618,11 +626,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..9b7a1c1 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.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"],
+        },
+    },
+}