Merge "Migrate CT demo app to Android" into main

This commit is contained in:
Sandro Montanari 2025-04-29 05:07:55 -07:00 • committed by Android (Google) Code Review
commit a7a37a8497
6 changed files with 319 additions and 0 deletions

View file

@ -0,0 +1,34 @@
// Copyright (C) 2025 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_team: "trendy_team_rubidium_sdk_runtime",
default_applicable_licenses: ["Android-Apache-2.0"],
}
android_app {
name: "CertificateTransparencyDemoApp",
manifest: "AndroidManifest.xml",
resource_dirs: ["res"],
srcs: [
"src/**/*.java",
],
static_libs: [
"androidx-constraintlayout_constraintlayout",
],
sdk_version: "current",
}

View file

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- /*
* Copyright (C) 2025 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.
*/ -->
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.android.ctdemo">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:label="@string/app_name"
android:networkSecurityConfig="@xml/network_security_config"
android:supportsRtl="true"
android:theme="@style/Theme.AppCompat.DayNight.NoActionBar"
tools:targetApi="34">
<profileable android:shell="true" />
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View file

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- /*
* Copyright (C) 2025 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.
*/ -->
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="32dp"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="32dp"
android:orientation="vertical"
tools:layout_editor_absoluteX="1dp">
<Button
android:id="@+id/button_wikipedia"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Connect to wikipedia.org" />
<Button
android:id="@+id/button_valid_badssl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Connect to sha256.badssl.com" />
<Button
android:id="@+id/button_no_sct_badssl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Connect to no-sct.badssl.com" />
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="10dp"
android:text="this is empty" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- /*
* Copyright (C) 2025 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.
*/ -->
<resources>
<string name="app_name">CTDemo</string>
</resources>

View file

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- /*
* Copyright (C) 2025 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.
*/ -->
<network-security-config>
<base-config>
<certificateTransparency enabled="true" />
</base-config>
</network-security-config>

View file

@ -0,0 +1,148 @@
/*
* Copyright (C) 2025 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.ctdemo;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Trace;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MainActivity extends AppCompatActivity {
Handler handler;
int cookie;
private void connectTo(String urlString, TextView textView) {
int myCookie = cookie++;
URL url = null;
long startTime = System.nanoTime();
Trace.beginAsyncSection("connectTo", myCookie);
try {
url = new URL(urlString);
} catch (MalformedURLException e) {
Trace.endAsyncSection("connectTo", myCookie);
handler.post(
new Runnable() {
@Override
public void run() {
textView.setText(e.toString());
}
});
return;
}
HttpURLConnection urlConnection = null;
try {
urlConnection = (HttpURLConnection) url.openConnection();
} catch (IOException e) {
Trace.endAsyncSection("connectTo", myCookie);
long estimatedTime = (System.nanoTime() - startTime) / 1000;
handler.post(
new Runnable() {
@Override
public void run() {
textView.setText("Failure in " + estimatedTime + " us");
}
});
return;
}
try {
InputStream in = new BufferedInputStream(urlConnection.getInputStream());
in.read();
} catch (IOException e) {
Trace.endAsyncSection("connectTo", myCookie);
long estimatedTime = (System.nanoTime() - startTime) / 1000;
handler.post(
new Runnable() {
@Override
public void run() {
textView.setText("Failure in " + estimatedTime + " us");
}
});
}
Trace.endAsyncSection("connectTo", myCookie);
long estimatedTime = (System.nanoTime() - startTime) / 1000;
handler.post(
new Runnable() {
@Override
public void run() {
textView.setText("Success in " + estimatedTime + " us");
}
});
urlConnection.disconnect();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ExecutorService executor = Executors.newSingleThreadExecutor();
handler = new Handler(Looper.getMainLooper());
Button buttonWikipedia = (Button) findViewById(R.id.button_wikipedia);
Button buttonValid = (Button) findViewById(R.id.button_valid_badssl);
Button buttonNoSCT = (Button) findViewById(R.id.button_no_sct_badssl);
final TextView textView = (TextView) findViewById(R.id.textView);
buttonWikipedia.setOnClickListener(
new View.OnClickListener() {
public void onClick(View v) {
executor.execute(
new Runnable() {
@Override
public void run() {
connectTo("https://www.android.com", textView);
}
});
}
});
buttonValid.setOnClickListener(
new View.OnClickListener() {
public void onClick(View v) {
executor.execute(
new Runnable() {
@Override
public void run() {
connectTo("https://sha256.badssl.com/", textView);
}
});
}
});
buttonNoSCT.setOnClickListener(
new View.OnClickListener() {
public void onClick(View v) {
executor.execute(
new Runnable() {
@Override
public void run() {
connectTo("https://no-sct.badssl.com/", textView);
}
});
}
});
}
}