Merge tag 'android-14.0.0_r29' into staging/lineage-21.0_merge-android-14.0.0_r29

Android 14.0.0 release 29

# -----BEGIN PGP SIGNATURE-----
#
# iF0EABECAB0WIQRDQNE1cO+UXoOBCWTorT+BmrEOeAUCZeZWvwAKCRDorT+BmrEO
# eK/mAJ9U9AMyANhfH6WaxLvEkgBf9OKt7wCdEQqKeW3Hs5CNZ03cEIt1mKMa6fA=
# =NEny
# -----END PGP SIGNATURE-----
# gpg: Signature made Tue Mar  5 01:18:23 2024 EET
# gpg:                using DSA key 4340D13570EF945E83810964E8AD3F819AB10E78
# gpg: Good signature from "The Android Open Source Project <initial-contribution@android.com>" [marginal]
# gpg: initial-contribution@android.com: Verified 2332 signatures in the past
#      2 years.  Encrypted 4 messages in the past 2 years.
# gpg: WARNING: This key is not certified with sufficiently trusted signatures!
# gpg:          It is not certain that the signature belongs to the owner.
# Primary key fingerprint: 4340 D135 70EF 945E 8381  0964 E8AD 3F81 9AB1 0E78

# By Andrew Walbran (83) and others
# Via Automerger Merge Worker (1775) and others
* tag 'android-14.0.0_r29': (423 commits)
  Add IME display policy support to VDM Demo
  VDM Host dedicated settings activity.
  cargo_embargo: add qwandor@ to OWNERS
  Fix Wifi Aware session check.
  VDM Demo connectivity fixes
  Support home intents on mirror displays
  Simplify the input handling in VDM Client
  Fullscreen support in VDM Client
  Pass cargo output around as string rather than writing to file.
  Fix a bunch of warnings in VDM Demo apps.
  VDM Client: Limit the resizing of virtual displays.
  compare_cts_reports: allow abi selection while parsing reports
  compare_cts_reports: support `ignore_abi` for csv report
  No hardcoded display dimensions in the VDM Client
  compare_cts_reports: do not show ignored ABI in the sheet
  Several changes to VDM Demo apps
  Fix external mouse in the VDM Client
  Use Future to attach Wifi Aware sesison syncronously.
  compare_cts_reports: add the `--ignore-abi` option
  Fix the connected icon in the VDM Host.
  ...

Change-Id: Id41e27a99face6f6c622510afaf173740ffd588f
This commit is contained in:
Michael Bestas
2024-03-09 00:29:03 +02:00
701 changed files with 104647 additions and 13243 deletions

View File

@@ -19,6 +19,8 @@ package {
filegroup {
name: "development_docs",
visibility: ["//visibility:private"],
visibility: [
"//art/test:__subpackages__",
],
srcs: ["docs/**/*"],
}

View File

@@ -6,3 +6,9 @@ ignore_merged_commits = true
[Hook Scripts]
winscope = ./tools/winscope/hooks/pre-upload ${PREUPLOAD_FILES}
checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT}
ktfmt_hook = ${REPO_ROOT}/external/ktfmt/ktfmt.py --check -i ${REPO_ROOT}/frameworks/base/ktfmt_includes.txt ${PREUPLOAD_FILES}
ktlint_hook = ${REPO_ROOT}/prebuilts/ktlint/ktlint.py --no-verify-format -f ${PREUPLOAD_FILES}

View File

@@ -43,9 +43,9 @@
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="com.google.android.googleapps.permission.ACCESS_GOOGLE_PASSWORD" />
<uses-permission android:name="com.google.android.googleapps.permission.GOOGLE_AUTH" />
<uses-permission android:name="com.google.android.googleapps.permission.GOOGLE_AUTH.ALL_SERVICES" />
<uses-permission android:name="com.google.android.googleapps.permission.GOOGLE_AUTH.YouTubeUser" />
<uses-permission android:name="com.google.android.googleapps.permission.GOOGLE_AUTH" android:maxSdkVersion="34"/>
<uses-permission android:name="com.google.android.googleapps.permission.GOOGLE_AUTH.ALL_SERVICES" android:maxSdkVersion="34"/>
<uses-permission android:name="com.google.android.googleapps.permission.GOOGLE_AUTH.YouTubeUser" android:maxSdkVersion="34"/>
<application android:label="Dev Tools"
android:icon="@mipmap/ic_launcher_devtools">
@@ -112,6 +112,12 @@
<category android:name="android.intent.category.TEST" />
</intent-filter>
</activity>
<activity android:name="HttpEngineActivity" android:label="Http Client" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.TEST" />
</intent-filter>
</activity>
<activity android:name="InstrumentationList" android:label="Instrumentation"
android:exported="true">

View File

@@ -0,0 +1,39 @@
<!-- Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingStart="@dimen/activity_horizontal_margin"
android:paddingEnd="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".CronetSampleActivity">
<TextView
android:id="@+id/resultView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/resultView">
<TextView
android:id="@+id/dataView"
android:clickable="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="26dp"/>
</ScrollView>
</RelativeLayout>

View File

@@ -0,0 +1,56 @@
<!-- Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="@+id/urlView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:layout_marginStart="4dp"
android:textSize="16sp"
android:text="@string/urlText" />
<!-- TODO(crbug.com/900912): Fix and remove lint ignore -->
<EditText
tools:ignore="LabelFor"
android:id="@+id/urlText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textUri" />
<TextView
android:id="@+id/postView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="26dp"
android:layout_marginStart="4dp"
android:textSize="16sp"
android:text="@string/postText" />
<!-- TODO(crbug.com/900912): Fix and remove lint ignore -->
<EditText
tools:ignore="LabelFor"
android:id="@+id/postText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text" />
</LinearLayout>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
</resources>

View File

@@ -225,4 +225,8 @@
<string name="scancard">Scan SD card</string>
<string name="numsongs"># of albums</string>
<string name="insertbutton">Insert %1s albums</string>
<!-- HttpEngineActivity -->
<string name="urlText">Enter a URL</string>
<string name="postText">Enter post data (leave it blank for GET request)</string>
</resources>

View File

@@ -0,0 +1,219 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.development;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.net.http.HttpEngine;
import android.net.http.HttpException;
import android.net.http.UploadDataProvider;
import android.net.http.UploadDataSink;
import android.net.http.UrlRequest;
import android.net.http.UrlResponseInfo;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.WritableByteChannel;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
/**
* Activity for managing HttpEngine interactions.
*/
public class HttpEngineActivity extends Activity {
private static final String TAG = HttpEngineActivity.class.getSimpleName();
private HttpEngine mHttpEngine;
private String mUrl;
private TextView mResultText;
private TextView mReceiveDataText;
class SimpleUrlRequestCallback implements UrlRequest.Callback {
private ByteArrayOutputStream mBytesReceived = new ByteArrayOutputStream();
private WritableByteChannel mReceiveChannel = Channels.newChannel(mBytesReceived);
@Override
public void onRedirectReceived(
UrlRequest request, UrlResponseInfo info, String newLocationUrl) {
Log.i(TAG, "****** onRedirectReceived ******");
request.followRedirect();
}
@Override
public void onResponseStarted(UrlRequest request, UrlResponseInfo info) {
Log.i(TAG, "****** Response Started ******");
Log.i(TAG, "*** Headers Are *** " + info.getHeaders());
request.read(ByteBuffer.allocateDirect(32 * 1024));
}
@Override
public void onReadCompleted(
UrlRequest request, UrlResponseInfo info, ByteBuffer byteBuffer) {
byteBuffer.flip();
Log.i(TAG, "****** onReadCompleted ******" + byteBuffer);
try {
mReceiveChannel.write(byteBuffer);
} catch (IOException e) {
Log.i(TAG, "IOException during ByteBuffer read. Details: ", e);
}
byteBuffer.clear();
request.read(byteBuffer);
}
@Override
public void onSucceeded(UrlRequest request, UrlResponseInfo info) {
Log.i(TAG, "****** Request Completed, status code is " + info.getHttpStatusCode()
+ ", total received bytes is " + info.getReceivedByteCount());
final String receivedData = mBytesReceived.toString();
final String url = info.getUrl();
final String text = "Completed " + url + " (" + info.getHttpStatusCode() + ")";
HttpEngineActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
mResultText.setText(text);
mReceiveDataText.setText(receivedData);
promptForURL(url);
}
});
}
@Override
public void onFailed(UrlRequest request, UrlResponseInfo info, HttpException error) {
Log.i(TAG, "****** onFailed, error is: " + error.getMessage());
final String url = mUrl;
final String text = "Failed " + mUrl + " (" + error.getMessage() + ")";
HttpEngineActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
mResultText.setText(text);
promptForURL(url);
}
});
}
@Override
public void onCanceled(UrlRequest request, UrlResponseInfo info) {
Log.i(TAG, "****** onCanceled ******");
}
}
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.http_engine_activity);
mResultText = (TextView) findViewById(R.id.resultView);
mReceiveDataText = (TextView) findViewById(R.id.dataView);
mReceiveDataText.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
promptForURL(mUrl);
}
});
HttpEngine.Builder myBuilder = new HttpEngine.Builder(this);
myBuilder.setEnableHttpCache(HttpEngine.Builder.HTTP_CACHE_IN_MEMORY, 100 * 1024)
.setEnableHttp2(true)
.setEnableQuic(true);
mHttpEngine = myBuilder.build();
String appUrl = (getIntent() != null ? getIntent().getDataString() : null);
if (appUrl == null) {
promptForURL("https://");
} else {
startWithURL(appUrl);
}
}
private void promptForURL(String url) {
Log.i(TAG, "No URL provided via intent, prompting user...");
AlertDialog.Builder alert = new AlertDialog.Builder(this);
alert.setTitle("Enter a URL");
LayoutInflater inflater = getLayoutInflater();
View alertView = inflater.inflate(R.layout.http_engine_dialog, null);
final EditText urlInput = (EditText) alertView.findViewById(R.id.urlText);
urlInput.setText(url);
final EditText postInput = (EditText) alertView.findViewById(R.id.postText);
alert.setView(alertView);
alert.setPositiveButton("Load", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int button) {
String url = urlInput.getText().toString();
String postData = postInput.getText().toString();
startWithURL(url, postData);
}
});
alert.show();
}
private void applyPostDataToUrlRequestBuilder(
UrlRequest.Builder builder, Executor executor, String postData) {
if (postData != null && postData.length() > 0) {
builder.setHttpMethod("POST");
builder.addHeader("Content-Type", "application/x-www-form-urlencoded");
// TODO: make android.net.http.apihelpers.UploadDataProviders accessible.
builder.setUploadDataProvider(new UploadDataProvider() {
@Override
public long getLength() {
return postData.length();
}
@Override
public void read(UploadDataSink uploadDataSink, ByteBuffer byteBuffer) {
byteBuffer.put(postData.getBytes());
uploadDataSink.onReadSucceeded(/*finalChunk*/ false);
}
@Override
public void rewind(UploadDataSink uploadDataSink) {
// noop
uploadDataSink.onRewindSucceeded();
}
}, executor);
}
}
private void startWithURL(String url) {
startWithURL(url, null);
}
private void startWithURL(String url, String postData) {
Log.i(TAG, "UrlRequest started: " + url);
mUrl = url;
Executor executor = Executors.newSingleThreadExecutor();
UrlRequest.Callback callback = new SimpleUrlRequestCallback();
UrlRequest.Builder builder = mHttpEngine.newUrlRequestBuilder(url, executor, callback);
applyPostDataToUrlRequestBuilder(builder, executor, postData);
builder.build().start();
}
}

View File

@@ -11,7 +11,9 @@ android_test {
name: "PushApiAuthenticator",
// Only compile source java files in this apk.
srcs: ["src/**/*.java"],
sdk_version: "current",
sdk_version: "26",
target_sdk_version: "26",
min_sdk_version: "26",
dex_preopt: {
enabled: false,
},

View File

@@ -19,9 +19,10 @@
package="com.example.android.pushapiauthenticator">
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS"/>
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
<!-- Uses API introduced in O (26) -->
<uses-sdk android:minSdkVersion="1"
android:targetSdkVersion="26"/>
android:targetSdkVersion="30"/>
<application android:label="Auth Tester" android:icon="@drawable/push">
<activity android:name="MainActivity">
<intent-filter>

View File

@@ -171,14 +171,14 @@
<RadioButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="SET UM_NOT_VISIBLE(4)"
android:text="SET UM_NOT_VISIBLE (4)"
android:id="@+id/notVisibleButton"
android:checked="false" />
<RadioButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="SET NOT_VISIBLE(3)"
android:text="SET NOT_VISIBLE (3)"
android:id="@+id/forcedNotVisibleButton"
android:checked="false" />

View File

@@ -161,7 +161,7 @@ public class MainActivity extends Activity {
am.setAccountVisibility(currentAccount, packageName,
AccountManager.VISIBILITY_USER_MANAGED_VISIBLE);
Toast.makeText(
getApplicationContext(), "Set UM_VISIBLE(2) "
getApplicationContext(), "Set UM_VISIBLE (2) "
+ currentAccount.name + " to " + packageName,
Toast.LENGTH_SHORT).show();
break;
@@ -169,7 +169,7 @@ public class MainActivity extends Activity {
am.setAccountVisibility(currentAccount, packageName,
AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE);
Toast.makeText(
getApplicationContext(), "Set UM_NOT_VISIBLE(4) "
getApplicationContext(), "Set UM_NOT_VISIBLE (4) "
+ currentAccount.name + " to " + packageName,
Toast.LENGTH_SHORT).show();
break;
@@ -177,20 +177,21 @@ public class MainActivity extends Activity {
am.setAccountVisibility(currentAccount, packageName,
AccountManager.VISIBILITY_NOT_VISIBLE);
Toast.makeText(
getApplicationContext(), "Removing visibility(3) "
getApplicationContext(), "Removing visibility (3) "
+ currentAccount.name + " of " + packageName,
Toast.LENGTH_SHORT).show();
break;
case R.id.getButton:
Toast.makeText(getApplicationContext(),
"Is " + currentAccount.name + " visible to " + packageName
+ "?\n"
+ am.getAccountVisibility(currentAccount, packageName),
"Visibility = "
+ am.getAccountVisibility(currentAccount, packageName)
+ " for " + currentAccount.name + ", app= "
+ packageName,
Toast.LENGTH_SHORT).show();
break;
case R.id.addAccountButton:
Toast.makeText(getApplicationContext(),
"Adding account explicitly!"
"Adding account "
+ am.addAccountExplicitly(currentAccount, null, null),
Toast.LENGTH_SHORT).show();
break;
@@ -199,7 +200,7 @@ public class MainActivity extends Activity {
packageAndVisibilitys.put(packageName,
AccountManager.VISIBILITY_USER_MANAGED_VISIBLE);
Toast.makeText(getApplicationContext(),
"Adding account explicitly!"
"Adding account "
+ am.addAccountExplicitly(currentAccount, null, null,
packageAndVisibilitys)
+ " with visibility for " + packageName + "!",
@@ -207,7 +208,7 @@ public class MainActivity extends Activity {
break;
case R.id.removeAccount:
Toast.makeText(getApplicationContext(),
"Removing account explicitly!"
"Removing account "
+ am.removeAccountExplicitly(currentAccount),
Toast.LENGTH_SHORT).show();
break;

View File

@@ -190,7 +190,6 @@ android_sdk_repo_host {
deps: [
"adb",
"dmtracedump",
"etc1tool",
"fastboot",
"hprof-conv",
@@ -221,7 +220,6 @@ android_sdk_repo_host {
not_windows: {
strip_files: [
"adb",
"dmtracedump",
"etc1tool",
"fastboot",
"hprof-conv",

View File

@@ -1,261 +0,0 @@
#!/usr/bin/env python2
#
# Copyright (C) 2011 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.
#
import re
import os
import sys
import getopt
import shutil
import subprocess
import zipfile
VERBOSE = False
TOP_FOLDER = "src"
_RE_PKG = re.compile("^\s*package\s+([^\s;]+)\s*;.*")
# Holds cmd-line arguments and context information
class Params(object):
def __init__(self):
self.EXEC_ZIP = False
self.DRY = False
self.PROPS = None
self.SRC = None
self.DST = None
self.CNT_USED = 0
self.CNT_NOPKG = 0
# DIR is the list of directories to scan in TOPDIR.
self.DIR = "frameworks libcore"
self.IGNORE_DIR = [ "hosttests", "tools", "tests", "samples", "layoutlib" ]
# IGNORE is a list of namespaces to ignore. Must be java
# package definitions (e.g. "com.blah.foo.")
self.IGNORE = [ "sun.", "libcore.", "dalvik.",
"com.test.", "com.google.",
"coretestutils.", "test.", "test2.", "tests." ]
self.zipfile = None
def verbose(msg, *args):
"""Prints a verbose message to stderr if --verbose is set."""
global VERBOSE
if VERBOSE:
if args:
msg = msg % args
print >>sys.stderr, msg
# Prints a usage summary
def usage(error=None):
print """
Description:
This script collects all framework Java sources from the current android
source code and places them in a source.zip file that can be distributed
by the SDK Manager.
Usage:
%s [-n|-v|-z] <source.properties> <sources.zip> <topdir>
The source.properties file must exist and will be injected in the Zip file.
The source directory must already exist.
Use -v for verbose output (lists each file being picked up or ignored).
Use -n for a dry-run (doesn't write the zip file).
Use -z to use the system 'zip' command instead of the Python Zip module.
""" % sys.argv[0]
if error:
print >>sys.stderr, "Error:", error
# Parse command line args, returns a Params instance or sys.exit(2) on error
# after printing the error and the usage.
def parseArgs(argv):
global VERBOSE
p = Params()
error = None
try:
opts, args = getopt.getopt(argv[1:],
"zvns:",
[ "exec-zip", "verbose", "dry", "sourcedir=" ])
except getopt.GetoptError, e:
error = str(e)
if error is None:
for o, a in opts:
if o in [ "-n", "--dry" ]:
# Dry mode: don't copy/zip, print what would be done.
p.DRY = True
if o in [ "-v", "--verbose" ]:
# Verbose mode. Display everything that's going on.
VERBOSE = True
elif o in [ "-s", "--sourcedir" ]:
# The source directories to process (space separated list)
p.DIR = a
elif o in [ "-z", "--exec-zip" ]:
# Don't use Python zip, instead call the 'zip' system exec.
p.EXEC_ZIP = True
if len(args) != 3:
error = "Missing arguments: <source> <dest>"
else:
p.PROPS = args[0]
p.DST = args[1]
p.SRC = args[2]
if not os.path.isfile(p.PROPS):
error = "%s is not a file" % p.PROPS
if not os.path.isdir(p.SRC):
error = "%s is not a directory" % p.SRC
if error:
usage(error)
sys.exit(2)
return p
# Recursively parses the given directory and processes java files found
def parseSrcDir(p, srcdir):
if not os.path.exists(srcdir):
verbose("Error: Skipping unknown directory %s", srcdir)
return
for filename in os.listdir(srcdir):
filepath = os.path.join(srcdir, filename)
if filename.endswith(".java") and os.path.isfile(filepath):
pkg = checkJavaFile(filepath)
if not pkg:
verbose("No package found in %s", filepath)
if pkg:
# Should we ignore this package?
pkg2 = pkg
if not "." in pkg2:
pkg2 += "."
for ignore in p.IGNORE:
if pkg2.startswith(ignore):
verbose("Ignore package %s [%s]", pkg, filepath)
pkg = None
break
if pkg:
pkg = pkg.replace(".", os.path.sep) # e.g. android.view => android/view
copy(p, filepath, pkg)
p.CNT_USED += 1
else:
p.CNT_NOPKG += 1
elif os.path.isdir(filepath):
if not filename in p.IGNORE_DIR:
parseSrcDir(p, filepath)
# Check a java file to find its package declaration, if any
def checkJavaFile(path):
try:
f = None
try:
f = file(path)
for l in f.readlines():
m = _RE_PKG.match(l)
if m:
return m.group(1)
finally:
if f: f.close()
except Exception:
pass
return None
USED_ARC_PATH = {}
# Copy the given file (given its absolute filepath) to
# the relative desk_pkg directory in the zip file.
def copy(p, filepath, dest_pkg):
arc_path = os.path.join(TOP_FOLDER, dest_pkg, os.path.basename(filepath))
if arc_path in USED_ARC_PATH:
verbose("Ignore duplicate archive path %s", arc_path)
USED_ARC_PATH[arc_path] = 1
if p.DRY:
print >>sys.stderr, "zip %s [%s]" % (arc_path, filepath)
elif p.zipfile is not None:
if p.EXEC_ZIP:
# zipfile is a path. Copy to it.
dest_path = os.path.join(p.zipfile, arc_path)
dest_dir = os.path.dirname(dest_path)
if not os.path.isdir(dest_dir):
os.makedirs(dest_dir)
shutil.copyfile(filepath, dest_path)
else:
# zipfile is a ZipFile object. Compress with it.
p.zipfile.write(filepath, arc_path)
def shellExec(*cmd):
"""
Executes the given system command.
The command must be split into a list (c.f. shext.split().)
This raises an exception if the command fails.
Stdin/out/err are not being redirected.
"""
verbose("exec: %s", repr(cmd))
subprocess.check_call(cmd)
def main():
p = parseArgs(sys.argv)
z = None
try:
if not p.DRY:
if p.EXEC_ZIP:
p.zipfile = p.DST + "_temp_dir"
if os.path.exists(p.zipfile):
shutil.rmtree(p.zipfile)
props_dest = os.path.join(p.zipfile, TOP_FOLDER + "/source.properties")
os.makedirs(os.path.dirname(props_dest))
shutil.copyfile(p.PROPS, props_dest)
else:
p.zipfile = z = zipfile.ZipFile(p.DST, "w", zipfile.ZIP_DEFLATED)
z.write(p.PROPS, TOP_FOLDER + "/source.properties")
for d in p.DIR.split():
if d:
parseSrcDir(p, os.path.join(p.SRC, d))
if p.EXEC_ZIP and not p.DRY:
curr_dir = os.getcwd()
os.chdir(p.zipfile)
if os.path.exists("_temp.zip"):
os.unlink("_temp.zip");
shellExec("zip", "-9r", "_temp.zip", TOP_FOLDER)
os.chdir(curr_dir)
shutil.move(os.path.join(p.zipfile, "_temp.zip"), p.DST)
shutil.rmtree(p.zipfile)
finally:
if z is not None:
z.close()
print "%s: %d java files copied" % (p.DST, p.CNT_USED)
if p.CNT_NOPKG:
print "%s: %d java files ignored" % (p.DST, p.CNT_NOPKG)
if p.DRY:
print >>sys.stderr, "This was in *DRY* mode. No copies done."
if __name__ == "__main__":
main()
# For emacs:
# -*- tab-width: 4; -*-

View File

@@ -15,7 +15,7 @@ SDK_SYSIMG_XML_ARGS :=
# $3=package to create (e.g. tools, docs, etc.)
#
define sdk-repo-pkg-zip
$(dir $(2))/sdk-repo-$(1)-$(3)-$(FILE_NAME_TAG).zip
$(dir $(2))/sdk-repo-$(1)-$(3).zip
endef
# Defines the rule to build an SDK repository package by zipping all
@@ -33,10 +33,9 @@ endef
define mk-sdk-repo-pkg-1
$(call sdk-repo-pkg-zip,$(2),$(3),$(4)): $(3)
@echo "Building SDK repository package $(4) from $(notdir $(3))"
$(hide) cd $(basename $(3)) && \
rm -f ../$(notdir $(call sdk-repo-pkg-zip,$(2),$(3),$(4))) && \
zip -9rq ../$(notdir $(call sdk-repo-pkg-zip,$(2),$(3),$(4))) $(4)/*
$(call dist-for-goals, sdk_repo, $(call sdk-repo-pkg-zip,$(2),$(3),$(4)))
$(hide) rm -f $$@ && \
$(SOONG_ZIP) -o $$@ -C $(basename $(3)) -D $(basename $(3))/$(4)
$(call dist-for-goals-with-filenametag, sdk_repo, $(call sdk-repo-pkg-zip,$(2),$(3),$(4)))
$(1) += $(4) $(2) \
$(call sdk-repo-pkg-zip,$(2),$(3),$(4)):$(notdir $(call sdk-repo-pkg-zip,$(2),$(3),$(4)))
@@ -59,40 +58,9 @@ endef
define mk-sdk-repo-pkg-2
$(call sdk-repo-pkg-zip,$(2),$(3),$(4)): $(3)
@echo "Building SDK repository package $(4) from $(notdir $(3))"
$(hide) cd $(basename $(3))/$(4) && \
rm -f ../../$(notdir $(call sdk-repo-pkg-zip,$(2),$(3),$(4))) && \
zip -9rq ../../$(notdir $(call sdk-repo-pkg-zip,$(2),$(3),$(4))) *
$(call dist-for-goals, sdk_repo, $(call sdk-repo-pkg-zip,$(2),$(3),$(4)))
$(1) += $(4) $(2) \
$(call sdk-repo-pkg-zip,$(2),$(3),$(4)):$(notdir $(call sdk-repo-pkg-zip,$(2),$(3),$(4)))
$(call declare-1p-container,$(call sdk-repo-pkg-zip,$(2),$(3),$(4)),sdk_repo)
$(call declare-container-license-deps,$(call sdk-repo-pkg-zip,$(2),$(3),$(4)),$(3),$(PRODUCT_OUT)/:/)
endef
# Defines the rule to build an SDK repository package when the
# package directory contains 3 levels from the sdk dir, for example
# to package SDK/extra/android/support or SDK/system-images/android-N/armeabi.
# Because we do not know the intermediary directory name, this only works
# if each directory contains a single sub-directory (e.g. sdk/$4/*/* must be
# unique.)
#
# $1=variable where to accumulate args for mk_sdk_repo_xml.
# $2=OS (e.g. linux, darwin)
# $3=sdk zip (e.g. out/host/linux.../android-eng-sdk.zip)
# $4=package to create (e.g. system-images, support, etc.)
# $5=the root of directory to package in the sdk (e.g. extra/android).
# this must be a 2-segment path, the last one can be *.
#
# The rule depends on the SDK zip file, which is defined by $2.
#
define mk-sdk-repo-pkg-3
$(call sdk-repo-pkg-zip,$(2),$(3),$(4)): $(3)
@echo "Building SDK repository package $(4) from $(notdir $(3))"
$(hide) cd $(basename $(3))/$(5) && \
rm -f ../../../$(notdir $(call sdk-repo-pkg-zip,$(2),$(3),$(4))) && \
zip -9rq ../../../$(notdir $(call sdk-repo-pkg-zip,$(2),$(3),$(4))) *
$(call dist-for-goals, sdk_repo, $(call sdk-repo-pkg-zip,$(2),$(3),$(4)))
$(hide) rm -f $$@ && \
$(SOONG_ZIP) -o $$@ -C $(basename $(3))/$(4) -D $(basename $(3))/$(4)
$(call dist-for-goals-with-filenametag, sdk_repo, $(call sdk-repo-pkg-zip,$(2),$(3),$(4)))
$(1) += $(4) $(2) \
$(call sdk-repo-pkg-zip,$(2),$(3),$(4)):$(notdir $(call sdk-repo-pkg-zip,$(2),$(3),$(4)))
@@ -108,12 +76,15 @@ endef
# $4=package to create, must be "sources"
#
define mk-sdk-repo-sources
$(call sdk-repo-pkg-zip,$(2),$(3),$(4)): $(3) development/build/tools/mk_sources_zip.py $(HOST_OUT)/development/sdk/source_source.properties
bcp_srcjar := $(call intermediates-dir-for,ETC,platform-bootclasspath.srcjar)/platform-bootclasspath.srcjar
source_props := $(HOST_OUT)/development/sdk/source_source.properties
$(call sdk-repo-pkg-zip,$(2),$(3),$(4)): $(3) $$(bcp_srcjar) $$(source_props)
@echo "Building SDK sources package"
development/build/tools/mk_sources_zip.py --exec-zip \
$(HOST_OUT)/development/sdk/source_source.properties \
$$@ .
$(call dist-for-goals, sdk_repo, $(call sdk-repo-pkg-zip,$(2),$(3),$(4)))
rm -rf $$(dir $$@)/tmp
unzip -qd $$(dir $$@)/tmp $$(bcp_srcjar)
$$(SOONG_ZIP) -o $$@ -P src -e source.properties -f $$(source_props) -C $$(dir $$@)/tmp -D $$(dir $$@)/tmp
rm -rf $$(dir $$@)/tmp
$(call dist-for-goals-with-filenametag, sdk_repo, $(call sdk-repo-pkg-zip,$(2),$(3),$(4)))
$(1) += $(4) $(2) \
$(call sdk-repo-pkg-zip,$(2),$(3),$(4)):$(notdir $(call sdk-repo-pkg-zip,$(2),$(3),$(4)))
@@ -266,7 +237,6 @@ SDK_SYSIMG_XML_ARGS :=
mk-sdk-repo-pkg-1 :=
mk-sdk-repo-pkg-2 :=
mk-sdk-repo-pkg-3 :=
mk-sdk-repo-sources :=
mk-sdk-repo-xml :=
sdk-repo-pkg-zip :=

View File

@@ -12,3 +12,29 @@ java_binary {
srcs: ["**/*.java"],
wrapper: "monkey.sh",
}
android_test {
// This test does not need to run on device. It's a regular Java unit test. But it needs to
// access some framework code like MotionEvent, KeyEvent, InputDevice, etc, which is currently
// not available for the host.
// Therefore, we are relying on 'android_test' here until ravenwood is ready.
name: "monkey_test",
srcs: ["**/*.java",
"**/*.kt",
],
kotlincflags: [
"-Werror",
],
static_libs: [
"androidx.test.runner",
],
libs: [
"junit",
],
test_suites: [
"general-tests",
],
}

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 The Android Open Source Project
<!-- Copyright 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -13,18 +13,10 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- Sample manifest file used for unit testing -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.tests">
<application>
<uses-library android:name="android.test.runner" />
</application>
<instrumentation android:name="android.test.InstrumentationTestRunner"
android:targetPackage="com.example.android"
android:label="Tests"/>
package="com.android.commands.monkey">
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="com.android.commands.monkey"
android:label="Monkey Test"/>
</manifest>

View File

@@ -550,6 +550,16 @@ public class Monkey {
commandLineReport(bugreportName + ".txt", "bugreport");
}
// UncaughtExceptionHandler set by RuntimeInit will report crash to system_server, which
// is not necessary for monkey and even causes deadlock. So we override it.
private static class KillSelfHandler implements Thread.UncaughtExceptionHandler {
@Override
public void uncaughtException(Thread t, Throwable e) {
Process.killProcess(Process.myPid());
System.exit(10);
}
}
/**
* Command-line entry point.
*
@@ -559,6 +569,7 @@ public class Monkey {
// Set the process name showing in "ps" or "top"
Process.setArgV0("com.android.commands.monkey");
Thread.setDefaultUncaughtExceptionHandler(new KillSelfHandler());
Logger.err.println("args: " + Arrays.toString(args));
int resultCode = (new Monkey()).run(args);
System.exit(resultCode);

View File

@@ -19,6 +19,7 @@ package com.android.commands.monkey;
import android.app.ActivityManager;
import android.app.AppGlobals;
import android.app.IActivityManager;
import android.content.Context;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.PermissionInfo;
@@ -49,10 +50,11 @@ public class MonkeyPermissionEvent extends MonkeyEvent {
Logger.out.println(String.format(":Permission %s %s to package %s",
grant ? "grant" : "revoke", mPermissionInfo.name, mPkg));
if (grant) {
permissionManager.grantRuntimePermission(mPkg, mPermissionInfo.name, currentUser);
permissionManager.grantRuntimePermission(mPkg, mPermissionInfo.name,
Context.DEVICE_ID_DEFAULT, currentUser);
} else {
permissionManager.revokeRuntimePermission(mPkg, mPermissionInfo.name, currentUser,
null);
permissionManager.revokeRuntimePermission(mPkg, mPermissionInfo.name,
Context.DEVICE_ID_DEFAULT, currentUser, null);
}
return MonkeyEvent.INJECT_SUCCESS;
} catch (RemoteException re) {

View File

@@ -17,6 +17,7 @@
package com.android.commands.monkey;
import android.Manifest;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
@@ -106,7 +107,8 @@ public class MonkeyPermissionUtil {
}
private boolean shouldTargetPermission(String pkg, PermissionInfo pi) throws RemoteException {
int flags = mPermManager.getPermissionFlags(pkg, pi.name, UserHandle.myUserId());
int flags = mPermManager.getPermissionFlags(pkg, pi.name, Context.DEVICE_ID_DEFAULT,
UserHandle.myUserId());
int fixedPermFlags = PackageManager.FLAG_PERMISSION_SYSTEM_FIXED
| PackageManager.FLAG_PERMISSION_POLICY_FIXED;
return pi.group != null && pi.protectionLevel == PermissionInfo.PROTECTION_DANGEROUS

View File

@@ -50,9 +50,9 @@ public class MonkeyRotationEvent extends MonkeyEvent {
// inject rotation event
try {
iwm.freezeRotation(mRotationDegree);
iwm.freezeRotation(mRotationDegree, /* caller= */ "MonkeyRotationEven#injectEvent");
if (!mPersist) {
iwm.thawRotation();
iwm.thawRotation(/* caller= */ "MonkeyRotationEven#injectEvent");
}
return MonkeyEvent.INJECT_SUCCESS;
} catch (RemoteException ex) {

View File

@@ -580,9 +580,12 @@ public class MonkeySourceScript implements MonkeyEventSource {
y2, 1, 5));
}
eventTime = SystemClock.uptimeMillis();
mQ.addLast(new MonkeyTouchEvent(MotionEvent.ACTION_POINTER_UP)
mQ.addLast(new MonkeyTouchEvent(MotionEvent.ACTION_POINTER_UP
| (1 << MotionEvent.ACTION_POINTER_INDEX_SHIFT))
.setDownTime(downTime).setEventTime(eventTime).addPointer(0, x1, y1)
.addPointer(1, x2, y2));
mQ.addLast(new MonkeyTouchEvent(MotionEvent.ACTION_UP)
.setDownTime(downTime).setEventTime(eventTime).addPointer(0, x1, y1));
}
}

View File

@@ -0,0 +1,87 @@
/*
* Copyright 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.commands.monkey
import android.view.MotionEvent.ACTION_DOWN
import android.view.MotionEvent.ACTION_MOVE
import android.view.MotionEvent.ACTION_POINTER_DOWN
import android.view.MotionEvent.ACTION_POINTER_INDEX_SHIFT
import android.view.MotionEvent.ACTION_POINTER_UP
import android.view.MotionEvent.ACTION_UP
import java.io.BufferedWriter
import java.io.FileWriter
import java.io.File
import java.util.Random
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertNull
import org.junit.Test
private fun receiveEvent(script: MonkeySourceScript, type: Int): MonkeyEvent {
val event = script.getNextEvent()
assertNotNull(event)
assertEquals(type, event.getEventType())
return event
}
private fun assertTouchEvent(script: MonkeySourceScript, action: Int) {
val motionEvent = receiveEvent(script, MonkeyEvent.EVENT_TYPE_TOUCH) as MonkeyMotionEvent
assertEquals(action, motionEvent.getAction())
}
/**
* Test for class MonkeySourceScript
*/
class MonkeySourceScriptTest {
companion object {
const val ACTION_POINTER_1_DOWN = ACTION_POINTER_DOWN.or(1.shl(ACTION_POINTER_INDEX_SHIFT))
const val ACTION_POINTER_1_UP = ACTION_POINTER_UP.or(1.shl(ACTION_POINTER_INDEX_SHIFT))
}
/**
* Send a PinchZoom command and check the resulting event stream.
* Since ACTION_UP is a throttlable event, an event with TYPE_THROTTLE is expected at the end.
*/
@Test
fun pinchZoom() {
val file = File.createTempFile("pinch_zoom", null)
val fileName = file.getAbsolutePath()
BufferedWriter(FileWriter(fileName)).use { writer ->
writer.write("start data >>\n")
writer.write("PinchZoom(100,100,200,200,50,50,10,10,5)\n")
}
val script = MonkeySourceScript(Random(), fileName, 0, false, 0, 0)
assertTouchEvent(script, ACTION_DOWN)
assertTouchEvent(script, ACTION_POINTER_1_DOWN)
assertTouchEvent(script, ACTION_MOVE)
assertTouchEvent(script, ACTION_MOVE)
assertTouchEvent(script, ACTION_MOVE)
assertTouchEvent(script, ACTION_MOVE)
assertTouchEvent(script, ACTION_MOVE)
assertTouchEvent(script, ACTION_POINTER_1_UP)
assertTouchEvent(script, ACTION_UP)
receiveEvent(script, MonkeyEvent.EVENT_TYPE_THROTTLE)
assertNull(script.getNextEvent())
file.deleteOnExit()
}
}

View File

@@ -16,26 +16,26 @@ LOCAL_PATH := $(call my-dir)
KMI_CHK_SCRIPT := $(LOCAL_PATH)/kmi_compatibility_test.sh
# Current kernel symbol files to be checked
# Use the one under $(LOCAL_PATH)/sym-5.* by default for self testing.
# Use the one under $(LOCAL_PATH)/sym-[56].* by default for self testing.
# The reason not to use the one under kernel/prebuilts/5.* by default
# is because the KMI ABI may not be stable during development.
#
# Set CURR_5_15_SYMVERS/CURR_5_10_SYMVERS explicitly for the actual
# Set CURR_5_15_SYMVERS/CURR_6_1_SYMVERS explicitly for the actual
# current kernel symbol file to be checked. E.g.,
# $ m CURR_5_10_SYMVERS=kernel/prebuilts/5.10/arm64/vmlinux.symvers \
# gki_5_10_kmi_compatibility_test
CURR_5_15_SYMVERS ?= development/gki/kmi_abi_chk/sym-5.15/vmlinux.symvers
CURR_5_10_SYMVERS ?= development/gki/kmi_abi_chk/sym-5.10/vmlinux.symvers
# $ m CURR_6_1_SYMVERS=kernel/prebuilts/6.1/arm64/Module.symvers \
# gki_6_1_kmi_compatibility_test
CURR_5_15_SYMVERS ?= development/gki/kmi_abi_chk/sym-5.15/Module.symvers
CURR_6_1_SYMVERS ?= development/gki/kmi_abi_chk/sym-6.1/Module.symvers
# Previous kernel symbol files, against which the latest one is checked
# The file names of previous kernel symbol files are of this form:
# *.symvers-$(BID)
# Here *.symvers is a symbolic link to the latest build.
PREV_5_15_SYMVERS := $(LOCAL_PATH)/sym-5.15/vmlinux.symvers
PREV_5_10_SYMVERS := $(LOCAL_PATH)/sym-5.10/vmlinux.symvers
PREV_5_15_SYMVERS := $(LOCAL_PATH)/sym-5.15/Module.symvers
PREV_6_1_SYMVERS := $(LOCAL_PATH)/sym-6.1/Module.symvers
include $(CLEAR_VARS)
LOCAL_MODULE := a13_5_15_kmi_compatibility_test
LOCAL_MODULE := a14_5_15_kmi_compatibility_test
LOCAL_MODULE_CLASS := FAKE
LOCAL_MODULE_TAGS := optional
LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
@@ -48,21 +48,21 @@ $(LOCAL_BUILT_MODULE): $(KMI_CHK_SCRIPT) $(CURR_5_15_SYMVERS) $(PREV_5_15_SYMVER
$(hide) touch $@
include $(CLEAR_VARS)
LOCAL_MODULE := a13_5_10_kmi_compatibility_test
LOCAL_MODULE := a14_6_1_kmi_compatibility_test
LOCAL_MODULE_CLASS := FAKE
LOCAL_MODULE_TAGS := optional
LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
LOCAL_LICENSE_CONDITIONS := notice
include $(BUILD_SYSTEM)/base_rules.mk
$(LOCAL_BUILT_MODULE): $(KMI_CHK_SCRIPT) $(CURR_5_10_SYMVERS) $(PREV_5_10_SYMVERS)
$(LOCAL_BUILT_MODULE): $(KMI_CHK_SCRIPT) $(CURR_6_1_SYMVERS) $(PREV_6_1_SYMVERS)
@mkdir -p $(dir $@)
$(hide) $(KMI_CHK_SCRIPT) $(CURR_5_10_SYMVERS) $(PREV_5_10_SYMVERS)
$(hide) $(KMI_CHK_SCRIPT) $(CURR_6_1_SYMVERS) $(PREV_6_1_SYMVERS)
$(hide) touch $@
include $(CLEAR_VARS)
LOCAL_MODULE := a13_kmi_compatibility_test
LOCAL_REQUIRED_MODULES := a13_5_15_kmi_compatibility_test a13_5_10_kmi_compatibility_test
LOCAL_MODULE := a14_kmi_compatibility_test
LOCAL_REQUIRED_MODULES := a14_5_15_kmi_compatibility_test a14_6_1_kmi_compatibility_test
LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
LOCAL_LICENSE_CONDITIONS := notice
include $(BUILD_PHONY_PACKAGE)

View File

@@ -16,15 +16,18 @@
# Usage:
# development/gki/kmi_abi_chk/kmi_static_chk.sh \
# <current_symbol_info> <previous_symbol_info> ...
# <current_symbol_info> <previous_symbol_info> (abi_symbollist.report)
#
# abi_symbollist.report is from the previous/old GKI and optional.
# If it's not on the command line, all symbols from the previous/old GKI
# are considered KMI and will be checked.
if [[ "$#" -lt 2 ]]; then
echo "Usage: $0 <current_symbol_info> <previous_symbol_info> ..."
echo "Usage: $0 <current_symbol_info> <previous_symbol_info> (abi_symbollist.report)"
exit 1
fi
ret=0
for f in "$@"; do
for f in $1 $2; do
if [[ ! -e "$f" ]]; then
echo "Kernel symbol file $f does not exist!" >&2
ret=1
@@ -34,12 +37,25 @@ for f in "$@"; do
fi
done
unset abi_list
if [[ "$#" -gt 2 ]]; then
if [[ ! -e "$3" ]]; then
echo "ABI symbol list $3 does not exist!" >&2
ret=1
else
abi_list=$3
fi
fi
if [[ ! ret -eq 0 ]]; then
exit $ret
fi
tmp=$(mktemp /tmp/linux-symvers.XXXXXX)
trap "rm -f $tmp" EXIT
tmp_symvers_new=$(mktemp /tmp/linux-symvers.XXXXXX)
tmp_symvers_old=$(mktemp /tmp/linux-symvers.XXXXXX)
tmp_abi_lst_old=$(mktemp /tmp/linux-symvers.XXXXXX)
trap "rm -f $tmp_symvers_new tmp_symvers_old tmp_abi_lst_old" EXIT
curr=$1
shift
@@ -58,18 +74,29 @@ shift
# break KMI ABI, because the requirement is "relaxed". We want this case to
# pass so a keyword like "...EXPORT_SYMBOL" in the current symbol file can
# still match "...EXPORT_SYMBOL_GPL" in the previous symbol file.
grep "vmlinux.EXPORT_SYMBOL" $curr | sed 's/[ \t]*$//' > $tmp
grep "EXPORT_SYMBOL" $curr | sed 's/[ \t]*$//' > $tmp_symvers_new
if [[ -v abi_list ]]; then
awk '{print $1}' $abi_list > $tmp_abi_lst_old
echo "ABI list: $abi_list"
fi
echo "Current kernel symbol file, $curr, is checking against:"
for f in "$@"; do
for f in $1; do
if [[ -v abi_list ]]; then
grep -wf $tmp_abi_lst_old $f > $tmp_symvers_old
else
cp $f $tmp_symvers_old
fi
echo " $f"
# if nothing is found, grep returns 1, which means every symbol in the
# previous release (usually in *.symvers-$BID) can be found in the current
# release, so is considered successful here.
# if grep returns 0, which means some symbols are found in the previous
# symbol file but not in the current symbol file, then something wrong!
if grep -vf $tmp $f; then
if grep -vf $tmp_symvers_new $tmp_symvers_old; then
ret=1
echo "$f contains symbol(s) not found in, or incompatible with, $curr." >&2
fi

View File

@@ -0,0 +1 @@
Module.symvers-10342779

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
Module.symvers-10816536

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,177 @@
#!/usr/bin/env python3
#
# Copyright 2023 - The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Mix shared system images with a super image and disable vbmeta.
Example:
./development/gsi/repack_super_image/mix_ssi_with_device_image.py \
--device-image-files aosp_cf_arm64_phone-img.zip \
--ssi-files ssi-target_files.zip \
--misc-info misc_info.txt \
--ota-tools otatools.zip \
--output-dir ./output
or
ANDROID_PRODUCT_OUT=out/target/product/vsoc_arm64 \
ANDROID_HOST_OUT=out/host/linux-x86/ \
./development/gsi/repack_super_image/mix_ssi_with_device_image.py \
--ssi-files out/target/product/ssi/IMAGES/ \
--output-dir ./output
"""
import argparse
import os
import shutil
import subprocess
import tempfile
import zipfile
import repack_super_image
SSI_PARTITIONS = ["system", "system_ext", "product"]
def add_arguments(parser):
parser.add_argument("--device-image-files",
default=os.getenv("ANDROID_PRODUCT_OUT"),
help="The path to the img zip or directory containing "
"device images to be mixed with the given SSI. "
"Caution: If this is a directory, super.img and "
"vbmeta.img under this directory will be modified. "
"Default: $ANDROID_PRODUCT_OUT")
parser.add_argument("--ssi-files", required=True,
help="The path to the target_files zip or directory "
"containing shared system images for mixing.")
parser.add_argument("--ota-tools",
default=os.getenv("ANDROID_HOST_OUT"),
help="The path to the device OTA tools zip or directory "
"for mixing images. "
"Default: $ANDROID_HOST_OUT")
parser.add_argument("--misc-info",
help="The device misc_info.txt for mixing images. "
"Default: {args.device_image_files}/misc_info.txt.")
parser.add_argument("--output-dir",
help="The output directory for the mixed image. "
"Default: {args.device_image_files}.")
def unzip_ssi_images(ssi_target_files, output_dir):
"""Unzip shared system images from the target files zipfile."""
if not os.path.exists(ssi_target_files):
raise FileNotFoundError(f"{ssi_target_files} does not exist.")
with zipfile.ZipFile(ssi_target_files) as ssi_zip:
for part_img in SSI_PARTITIONS:
try:
ssi_zip.extract(f"IMAGES/{part_img}.img", output_dir)
except KeyError:
pass
return os.path.join(output_dir, "IMAGES")
def unzip_super_images(device_img_artifact, output_dir):
"""Unzip super.img from the device image artifact zipfile."""
if not os.path.exists(device_img_artifact):
raise FileNotFoundError(f"{device_img_artifact} does not exist.")
with zipfile.ZipFile(device_img_artifact) as device_img_zip:
device_img_zip.extract("super.img", output_dir)
return os.path.join(output_dir, "super.img")
def collect_ssi(ssi_dir):
"""Collect system, system_ext and product images for mixing."""
ssi_imgs = dict()
for part_img in SSI_PARTITIONS:
img_path = os.path.join(ssi_dir, f"{part_img}.img")
if os.path.exists(img_path):
ssi_imgs[part_img] = img_path
else:
# system.img is mandatory, while other images are optional in SSI
if part_img == "system":
raise FileNotFoundError(f"{img_path} does not exist.")
else:
print(f"No {part_img}.img")
ssi_imgs[part_img] = ""
return ssi_imgs
def main():
parser = argparse.ArgumentParser()
add_arguments(parser)
args = parser.parse_args()
if not args.device_image_files:
raise ValueError("device image path is not set.")
output_dir = args.output_dir if args.output_dir else args.device_image_files
if not os.path.isdir(output_dir):
raise ValueError(f"output directory {output_dir} is not valid.")
print(f"Output directory {output_dir}")
temp_dirs = []
try:
if os.path.isdir(args.ssi_files):
ssi_dir = args.ssi_files
else:
temp_dir = tempfile.mkdtemp(prefix="ssi_")
temp_dirs.append(temp_dir)
ssi_dir = unzip_ssi_images(args.ssi_files, temp_dir)
device_misc_info = args.misc_info
if os.path.isdir(args.device_image_files):
device_image_dir = args.device_image_files
super_img = os.path.join(device_image_dir, "super.img")
if not device_misc_info:
device_misc_info = os.path.join(device_image_dir, "misc_info.txt")
else:
super_img = unzip_super_images(args.device_image_files, output_dir)
if not device_misc_info or not os.path.exists(device_misc_info):
raise FileNotFoundError(f"misc_info {device_misc_info} does not exist.")
if not os.path.exists(super_img):
raise FileNotFoundError(f"{super_img} does not exist.")
if not args.ota_tools or not os.path.exists(args.ota_tools):
raise FileNotFoundError(f"otatools {args.ota_tools} does not exist.")
if os.path.isdir(args.ota_tools):
ota_tools_dir = args.ota_tools
else:
print("Unzip OTA tools.")
ota_tools_dir = tempfile.mkdtemp(prefix="ota_tools")
temp_dirs.append(ota_tools_dir)
with zipfile.ZipFile(args.ota_tools) as ota_tools_zip:
repack_super_image.unzip_ota_tools(ota_tools_zip, ota_tools_dir)
mix_part_imgs = collect_ssi(ssi_dir)
output_super_img = os.path.join(output_dir, "super.img")
repack_super_image.repack_super_image(ota_tools_dir, device_misc_info,
super_img, mix_part_imgs,
output_super_img)
print(f"Created mixed super.img at {output_super_img}")
avbtool_path = os.path.join(ota_tools_dir, "bin", "avbtool")
vbmeta_img = os.path.join(output_dir, "vbmeta.img")
subprocess.check_call([avbtool_path, "make_vbmeta_image",
"--flag", "2", "--output", vbmeta_img])
print(f"Created vbmeta.img at {vbmeta_img}")
finally:
for temp_dir in temp_dirs:
shutil.rmtree(temp_dir, ignore_errors=True)
if __name__ == "__main__":
main()

View File

@@ -117,6 +117,65 @@ def rewrite_misc_info(args_part_imgs, unpacked_part_imgs, lpmake_path,
return partition_names
def repack_super_image(ota_tools_dir, misc_info_path, super_img_path,
part_imgs, output_path):
temp_dirs = []
temp_files = []
try:
if not is_sparse_image(super_img_path):
raw_super_img = super_img_path
else:
print("Convert to unsparsed super image.")
simg2img_path = os.path.join(ota_tools_dir, BIN_DIR_NAME, "simg2img")
with tempfile.NamedTemporaryFile(
mode="wb", prefix="super", suffix=".img",
delete=False) as raw_super_img_file:
temp_files.append(raw_super_img_file.name)
raw_super_img = raw_super_img_file.name
subprocess.check_call([
simg2img_path, super_img_path, raw_super_img])
print("Unpack super image.")
unpacked_part_imgs = dict()
lpunpack_path = os.path.join(ota_tools_dir, BIN_DIR_NAME, "lpunpack")
unpack_dir = tempfile.mkdtemp(prefix="lpunpack")
temp_dirs.append(unpack_dir)
subprocess.check_call([lpunpack_path, raw_super_img, unpack_dir])
for file_name in os.listdir(unpack_dir):
if file_name.endswith(IMG_FILE_EXT):
part = file_name[:-len(IMG_FILE_EXT)]
unpacked_part_imgs[part] = os.path.join(unpack_dir, file_name)
print("Create temporary misc info.")
lpmake_path = os.path.join(ota_tools_dir, BIN_DIR_NAME, "lpmake")
with tempfile.NamedTemporaryFile(
mode="w", prefix="misc_info", suffix=".txt",
delete=False) as misc_info_file:
temp_files.append(misc_info_file.name)
misc_info_file_path = misc_info_file.name
with open(misc_info_path, "r") as misc_info:
part_list = rewrite_misc_info(part_imgs, unpacked_part_imgs,
lpmake_path, misc_info, misc_info_file)
# Check that all input partitions are in the partition list.
parts_not_found = part_imgs.keys() - set(part_list)
if parts_not_found:
raise ValueError("Cannot find partitions in misc info: " +
" ".join(parts_not_found))
print("Build super image.")
build_super_image_path = os.path.join(ota_tools_dir, BIN_DIR_NAME,
"build_super_image")
subprocess.check_call([build_super_image_path, misc_info_file_path,
output_path])
finally:
for temp_dir in temp_dirs:
shutil.rmtree(temp_dir, ignore_errors=True)
for temp_file in temp_files:
os.remove(temp_file)
def main():
parser = argparse.ArgumentParser(
description="This script is for test infrastructure to mix images in a "
@@ -161,69 +220,22 @@ def main():
if args.temp_dir:
tempfile.tempdir = args.temp_dir
temp_dirs = []
temp_files = []
temp_ota_tools_dir = None
try:
if os.path.isdir(args.ota_tools):
ota_tools_dir = args.ota_tools
else:
print("Unzip OTA tools.")
temp_ota_tools_dir = tempfile.mkdtemp(prefix="ota_tools")
temp_dirs.append(temp_ota_tools_dir)
with zipfile.ZipFile(args.ota_tools) as ota_tools_zip:
unzip_ota_tools(ota_tools_zip, temp_ota_tools_dir)
ota_tools_dir = temp_ota_tools_dir
if not is_sparse_image(args.super_img):
super_img_path = args.super_img
else:
print("Convert to unsparsed super image.")
simg2img_path = os.path.join(ota_tools_dir, BIN_DIR_NAME, "simg2img")
with tempfile.NamedTemporaryFile(
mode="wb", prefix="super", suffix=".img",
delete=False) as raw_super_img:
temp_files.append(raw_super_img.name)
super_img_path = raw_super_img.name
subprocess.check_call([simg2img_path, args.super_img, super_img_path])
print("Unpack super image.")
unpacked_part_imgs = dict()
lpunpack_path = os.path.join(ota_tools_dir, BIN_DIR_NAME, "lpunpack")
unpack_dir = tempfile.mkdtemp(prefix="lpunpack")
temp_dirs.append(unpack_dir)
subprocess.check_call([lpunpack_path, super_img_path, unpack_dir])
for file_name in os.listdir(unpack_dir):
if file_name.endswith(IMG_FILE_EXT):
part = file_name[:-len(IMG_FILE_EXT)]
unpacked_part_imgs[part] = os.path.join(unpack_dir, file_name)
print("Create temporary misc info.")
lpmake_path = os.path.join(ota_tools_dir, BIN_DIR_NAME, "lpmake")
with tempfile.NamedTemporaryFile(
mode="w", prefix="misc_info", suffix=".txt",
delete=False) as misc_info_file:
temp_files.append(misc_info_file.name)
misc_info_file_path = misc_info_file.name
with open(args.misc_info, "r") as misc_info:
part_list = rewrite_misc_info(args_part_imgs, unpacked_part_imgs,
lpmake_path, misc_info, misc_info_file)
# Check that all input partitions are in the partition list.
parts_not_found = args_part_imgs.keys() - set(part_list)
if parts_not_found:
raise ValueError("Cannot find partitions in misc info: " +
" ".join(parts_not_found))
print("Build super image.")
build_super_image_path = os.path.join(ota_tools_dir, BIN_DIR_NAME,
"build_super_image")
subprocess.check_call([build_super_image_path, misc_info_file_path,
args.super_img])
repack_super_image(ota_tools_dir, args.misc_info, args.super_img,
args_part_imgs, args.super_img)
finally:
for temp_dir in temp_dirs:
shutil.rmtree(temp_dir, ignore_errors=True)
for temp_file in temp_files:
os.remove(temp_file)
if temp_ota_tools_dir:
shutil.rmtree(temp_ota_tools_dir)
if __name__ == "__main__":

View File

@@ -7,7 +7,7 @@ try_add_subdir(allocator/aidl/vts/VtsHalGraphicsAllocatorAidl_TargetTest)
try_add_subdir(allocator/aidl/android.hardware.graphics.allocator-V2-ndk)
try_add_subdir(composer/aidl/android.hardware.graphics.composer3-V2-ndk)
try_add_subdir(composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest)
try_add_subdir(common/aidl/android.hardware.graphics.common-V4-ndk)
try_add_subdir(common/aidl/android.hardware.graphics.common-V5-ndk)
try_add_subdir(mapper/stable-c/libimapper_providerutils_tests)
try_add_subdir(mapper/stable-c/VtsHalGraphicsMapperStableC_TargetTest)
try_add_subdir(mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest)

View File

@@ -1,111 +1,93 @@
<code_scheme name="AndroidStyle">
<option name="JAVA_INDENT_OPTIONS">
<value>
<option name="INDENT_SIZE" value="4" />
<option name="CONTINUATION_INDENT_SIZE" value="8" />
<option name="TAB_SIZE" value="8" />
<option name="USE_TAB_CHARACTER" value="false" />
<option name="SMART_TABS" value="false" />
<option name="LABEL_INDENT_SIZE" value="0" />
<option name="LABEL_INDENT_ABSOLUTE" value="false" />
<option name="USE_RELATIVE_INDENTS" value="false" />
</value>
</option>
<option name="FIELD_NAME_PREFIX" value="m" />
<option name="STATIC_FIELD_NAME_PREFIX" value="s" />
<option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="9999" />
<option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="9999" />
<option name="IMPORT_LAYOUT_TABLE">
<value>
<package name="android" withSubpackages="true" static="true" />
<emptyLine />
<package name="androidx" withSubpackages="true" static="true" />
<emptyLine />
<package name="com.android" withSubpackages="true" static="true" />
<emptyLine />
<package name="dalvik" withSubpackages="true" static="true" />
<emptyLine />
<package name="libcore" withSubpackages="true" static="true" />
<emptyLine />
<package name="com" withSubpackages="true" static="true" />
<emptyLine />
<package name="gov" withSubpackages="true" static="true" />
<emptyLine />
<package name="junit" withSubpackages="true" static="true" />
<emptyLine />
<package name="net" withSubpackages="true" static="true" />
<emptyLine />
<package name="org" withSubpackages="true" static="true" />
<emptyLine />
<package name="java" withSubpackages="true" static="true" />
<emptyLine />
<package name="javax" withSubpackages="true" static="true" />
<emptyLine />
<package name="" withSubpackages="true" static="true" />
<emptyLine />
<package name="android" withSubpackages="true" static="false" />
<emptyLine />
<package name="androidx" withSubpackages="true" static="false" />
<emptyLine />
<package name="com.android" withSubpackages="true" static="false" />
<emptyLine />
<package name="dalvik" withSubpackages="true" static="false" />
<emptyLine />
<package name="libcore" withSubpackages="true" static="false" />
<emptyLine />
<package name="com" withSubpackages="true" static="false" />
<emptyLine />
<package name="gov" withSubpackages="true" static="false" />
<emptyLine />
<package name="junit" withSubpackages="true" static="false" />
<emptyLine />
<package name="net" withSubpackages="true" static="false" />
<emptyLine />
<package name="org" withSubpackages="true" static="false" />
<emptyLine />
<package name="java" withSubpackages="true" static="false" />
<emptyLine />
<package name="javax" withSubpackages="true" static="false" />
<emptyLine />
<package name="" withSubpackages="true" static="false" />
</value>
</option>
<code_scheme name="AndroidStyle" version="173">
<option name="RIGHT_MARGIN" value="100" />
<option name="JD_P_AT_EMPTY_LINES" value="false" />
<option name="JD_DO_NOT_WRAP_ONE_LINE_COMMENTS" value="true" />
<option name="JD_KEEP_EMPTY_PARAMETER" value="false" />
<option name="JD_KEEP_EMPTY_EXCEPTION" value="false" />
<option name="JD_KEEP_EMPTY_RETURN" value="false" />
<option name="JD_PRESERVE_LINE_FEEDS" value="true" />
<option name="KEEP_CONTROL_STATEMENT_IN_ONE_LINE" value="false" />
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
<option name="BLANK_LINES_AROUND_FIELD" value="1" />
<option name="BLANK_LINES_AFTER_CLASS_HEADER" value="1" />
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
<option name="ALIGN_MULTILINE_FOR" value="false" />
<option name="CALL_PARAMETERS_WRAP" value="1" />
<option name="METHOD_PARAMETERS_WRAP" value="1" />
<option name="EXTENDS_LIST_WRAP" value="1" />
<option name="THROWS_LIST_WRAP" value="1" />
<option name="EXTENDS_KEYWORD_WRAP" value="1" />
<option name="THROWS_KEYWORD_WRAP" value="1" />
<option name="METHOD_CALL_CHAIN_WRAP" value="1" />
<option name="BINARY_OPERATION_WRAP" value="1" />
<option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" />
<option name="TERNARY_OPERATION_WRAP" value="1" />
<option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" />
<option name="FOR_STATEMENT_WRAP" value="1" />
<option name="ARRAY_INITIALIZER_WRAP" value="1" />
<option name="ASSIGNMENT_WRAP" value="1" />
<option name="PLACE_ASSIGNMENT_SIGN_ON_NEXT_LINE" value="true" />
<option name="WRAP_COMMENTS" value="true" />
<option name="IF_BRACE_FORCE" value="3" />
<option name="DOWHILE_BRACE_FORCE" value="3" />
<option name="WHILE_BRACE_FORCE" value="3" />
<option name="FOR_BRACE_FORCE" value="3" />
<XML>
<option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" />
</XML>
<JavaCodeStyleSettings>
<option name="FIELD_NAME_PREFIX" value="m" />
<option name="STATIC_FIELD_NAME_PREFIX" value="s" />
<option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="9999" />
<option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="9999" />
<option name="IMPORT_LAYOUT_TABLE">
<value>
<package name="android" withSubpackages="true" static="true" />
<emptyLine />
<package name="androidx" withSubpackages="true" static="true" />
<emptyLine />
<package name="com.android" withSubpackages="true" static="true" />
<emptyLine />
<package name="dalvik" withSubpackages="true" static="true" />
<emptyLine />
<package name="libcore" withSubpackages="true" static="true" />
<emptyLine />
<package name="com" withSubpackages="true" static="true" />
<emptyLine />
<package name="gov" withSubpackages="true" static="true" />
<emptyLine />
<package name="junit" withSubpackages="true" static="true" />
<emptyLine />
<package name="kotlin" withSubpackages="true" static="true" />
<emptyLine />
<package name="net" withSubpackages="true" static="true" />
<emptyLine />
<package name="org" withSubpackages="true" static="true" />
<emptyLine />
<package name="java" withSubpackages="true" static="true" />
<emptyLine />
<package name="javax" withSubpackages="true" static="true" />
<emptyLine />
<package name="" withSubpackages="true" static="true" />
<emptyLine />
<package name="android" withSubpackages="true" static="false" />
<emptyLine />
<package name="androidx" withSubpackages="true" static="false" />
<emptyLine />
<package name="com.android" withSubpackages="true" static="false" />
<emptyLine />
<package name="dalvik" withSubpackages="true" static="false" />
<emptyLine />
<package name="libcore" withSubpackages="true" static="false" />
<emptyLine />
<package name="com" withSubpackages="true" static="false" />
<emptyLine />
<package name="dagger" withSubpackages="true" static="false" />
<emptyLine />
<package name="gov" withSubpackages="true" static="false" />
<emptyLine />
<package name="junit" withSubpackages="true" static="false" />
<emptyLine />
<package name="kotlin" withSubpackages="true" static="false" />
<emptyLine />
<package name="net" withSubpackages="true" static="false" />
<emptyLine />
<package name="org" withSubpackages="true" static="false" />
<emptyLine />
<package name="java" withSubpackages="true" static="false" />
<emptyLine />
<package name="javax" withSubpackages="true" static="false" />
<emptyLine />
<package name="" withSubpackages="true" static="false" />
</value>
</option>
<option name="JD_P_AT_EMPTY_LINES" value="false" />
<option name="JD_DO_NOT_WRAP_ONE_LINE_COMMENTS" value="true" />
<option name="JD_KEEP_EMPTY_PARAMETER" value="false" />
<option name="JD_KEEP_EMPTY_EXCEPTION" value="false" />
<option name="JD_KEEP_EMPTY_RETURN" value="false" />
<option name="JD_PRESERVE_LINE_FEEDS" value="true" />
</JavaCodeStyleSettings>
<JetCodeStyleSettings>
<option name="PACKAGES_IMPORT_LAYOUT">
<value>
<package name="" alias="false" withSubpackages="true" />
<package name="" alias="true" withSubpackages="true" />
</value>
</option>
<option name="CONTINUATION_INDENT_IN_PARAMETER_LISTS" value="false" />
<option name="CONTINUATION_INDENT_IN_ARGUMENT_LISTS" value="false" />
<option name="CONTINUATION_INDENT_FOR_EXPRESSION_BODIES" value="false" />
<option name="CONTINUATION_INDENT_IN_SUPERTYPE_LISTS" value="false" />
<option name="CONTINUATION_INDENT_IN_IF_CONDITIONS" value="false" />
<option name="CONTINUATION_INDENT_IN_ELVIS" value="false" />
<option name="WRAP_EXPRESSION_BODY_FUNCTIONS" value="1" />
</JetCodeStyleSettings>
<ADDITIONAL_INDENT_OPTIONS fileType="java">
<option name="TAB_SIZE" value="8" />
</ADDITIONAL_INDENT_OPTIONS>
@@ -129,6 +111,7 @@
<option name="FOR_STATEMENT_WRAP" value="1" />
<option name="ARRAY_INITIALIZER_WRAP" value="1" />
<option name="ASSIGNMENT_WRAP" value="1" />
<option name="WRAP_COMMENTS" value="true" />
<option name="IF_BRACE_FORCE" value="1" />
<option name="DOWHILE_BRACE_FORCE" value="1" />
<option name="WHILE_BRACE_FORCE" value="1" />
@@ -321,4 +304,21 @@
</rules>
</arrangement>
</codeStyleSettings>
<codeStyleSettings language="kotlin">
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
<option name="CALL_PARAMETERS_WRAP" value="5" />
<option name="METHOD_PARAMETERS_WRAP" value="5" />
<option name="EXTENDS_LIST_WRAP" value="5" />
<option name="METHOD_CALL_CHAIN_WRAP" value="5" />
<option name="ASSIGNMENT_WRAP" value="5" />
<option name="PARAMETER_ANNOTATION_WRAP" value="5" />
<option name="VARIABLE_ANNOTATION_WRAP" value="5" />
<option name="ENUM_CONSTANTS_WRAP" value="1" />
</codeStyleSettings>
<codeStyleSettings language="prototext">
<indentOptions>
<option name="INDENT_SIZE" value="4" />
<option name="TAB_SIZE" value="4" />
</indentOptions>
</codeStyleSettings>
</code_scheme>

View File

@@ -1,4 +0,0 @@
inseob@google.com
jeongik@google.com
justinyun@google.com
kiyoungkim@google.com

View File

@@ -1,69 +0,0 @@
#!/bin/bash -e
#
# Copyright (C) 2022 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.
#
function usage() {
cat <<EOF
Usage: $0 -d device-name -p product-name -r dist-dir -i build-id [targets]
Builds a vendor image for given product and analyze ninja inputs.
-d device name to build (e.g. vsoc_x86_64)
-p product name to build (e.g. cf_x86_64_phone)
-r directory for dist (e.g. out/dist)
-i build ID
-u whether it is an unbundled build
-h display this help and exit
EOF
exit 1
}
while getopts d:p:r:i:uh flag
do
case "${flag}" in
d) device=${OPTARG};;
p) product=${OPTARG};;
r) dist_dir=${OPTARG};;
i) build_id=${OPTARG};;
u) unbundled_build=true;;
h) usage;;
*) usage;;
esac
done
extra_targets=${@: ${OPTIND}}
if [[ -z "$device" || -z "$product" || -z "$dist_dir" || -z "$build_id" ]]; then
echo "missing arguments"
usage
fi
if [[ "$unbundled_build" = true ]]; then
export TARGET_BUILD_UNBUNDLED_IMAGE=true
fi
export ALLOW_MISSING_DEPENDENCIES=true
export SKIP_VNDK_VARIANTS_CHECK=true
export DIST_DIR=$dist_dir
build/soong/soong_ui.bash --make-mode vendorimage collect_ninja_inputs dist $extra_targets \
TARGET_PRODUCT=$product TARGET_BUILD_VARIANT=userdebug
cp out/target/product/$device/vendor.img $dist_dir
out/host/linux-x86/bin/collect_ninja_inputs -n prebuilts/build-tools/linux-x86/bin/ninja \
-f out/combined-$product.ninja -t vendorimage -m $dist_dir/manifest_$build_id.xml \
--out $dist_dir/logs/ninja_inputs

View File

@@ -1,129 +0,0 @@
#!/usr/bin/python3
#
# Copyright (C) 2023 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import xml.etree.ElementTree as ET
import json
import subprocess
import concurrent.futures
import requests
import os
import tempfile
import pprint
import sys
class BuildIdFinder:
def __init__(self, branch="aosp-master", target="aosp_cf_x86_64_phone-userdebug", batch_size=100):
local_branch = subprocess.getoutput(
"cat .repo/manifests/default.xml | grep super | sed 's/.*revision=\\\"\(.*\)\\\".*/\\1/'").strip()
text = subprocess.getoutput(
"repo forall -c 'echo \\\"$REPO_PROJECT\\\": \\\"$(git log m/" + local_branch + " --format=format:%H -1)\\\",'")
json_text = "{" + text[:-1] + "}"
self.local = json.loads(json_text)
self.branch = branch
self.target = target
self.batch_size = batch_size
def __rating(self, bid, target):
filename = "manifest_" + bid + ".xml"
fetch_result = subprocess.run(["/google/data/ro/projects/android/fetch_artifact", "--bid", bid,
"--target", target, filename], stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL)
if fetch_result.returncode != 0:
raise Exception('no artifact yet')
tree = ET.parse(filename)
root = tree.getroot()
remote = dict()
for child in root:
if child.tag == "project" and "revision" in child.attrib:
remote[child.attrib["name"]] = child.attrib["revision"]
common_key = self.local.keys() & remote.keys()
os.remove(filename)
return sum([self.local[key] != remote[key] for key in common_key])
def batch(self, nextPageToken="", best_rating=None):
result = dict()
url = "https://androidbuildinternal.googleapis.com/android/internal/build/v3/buildIds/%s?buildIdSortingOrder=descending&buildType=submitted&maxResults=%d" % (
self.branch, self.batch_size)
if nextPageToken != "":
url += "&pageToken=%s" % nextPageToken
res = requests.get(url)
bids = res.json()
best_rating_in_batch = None
with concurrent.futures.ThreadPoolExecutor(max_workers=20) as executor:
futures = {executor.submit(
self.__rating, bid_obj["buildId"], self.target): bid_obj["buildId"] for bid_obj in bids["buildIds"]}
for future in concurrent.futures.as_completed(futures):
try:
bid = futures[future]
different_prj_cnt = future.result()
if best_rating_in_batch is None:
best_rating_in_batch = different_prj_cnt
else:
best_rating_in_batch = min(
different_prj_cnt, best_rating_in_batch)
except Exception as exc:
# Ignore..
pass
else:
result[bid] = different_prj_cnt
if different_prj_cnt == 0:
return result
if best_rating is not None:
if best_rating < best_rating_in_batch:
# We don't need to try it further.
return result
result.update(self.batch(
nextPageToken=bids["nextPageToken"], best_rating=best_rating_in_batch))
return result
def main():
if len(sys.argv) == 1:
bif = BuildIdFinder()
elif len(sys.argv) == 3:
bif = BuildIdFinder(branch=sys.argv[1], target=sys.argv[2])
else:
print("""
Run without arguments or two arguments(branch and target)
It uses aosp-master and aosp_cf_x86_64_phone-userdebug by default.
For example,
./development/multitree/find_build_id.py
./development/multitree/find_build_id.py aosp-master aosp_cf_x86_64_phone-userdebug
""")
return
result = bif.batch()
best_rating = min(result.values())
best_bids = {k for (k, v) in result.items() if v == best_rating}
if best_rating == 0:
print("%s is the bid to use %s in %s for your repository" %
(best_bids, bif.target, bif.branch))
else:
print("""
Cannot find the perfect matched bid: There are 2 options
1. Choose a bid from the list below
(bids: %s, count of different projects: %s)
2. repo sync
""" % (best_bids, best_rating))
main()

View File

@@ -0,0 +1 @@
danalbert@google.com

View File

@@ -0,0 +1,64 @@
# fetchartifact
This is a Python interface to http://go/fetchartifact, which is used for
fetching artifacts from http://go/ab.
## Usage
```python
from fetchartifact import fetchartifact
async def main() -> None:
artifacts = await fetch_artifact(
branch="aosp-master-ndk",
target="linux",
build="1234",
pattern="android-ndk-*.zip",
)
for artifact in artifacts:
print(f"Downloaded {artifact}")
```
## Development
For first time set-up, install https://python-poetry.org/, then run
`poetry install` to install the project's dependencies.
This project uses mypy and pylint for linting, black and isort for
auto-formatting, and pytest for testing. All of these tools will be installed
automatically, but you may want to configure editor integration for them.
To run any of the tools poetry installed, you can either prefix all your
commands with `poetry run` (as in `poetry run pytest`), or you can run
`poetry shell` to enter a shell with all the tools on the `PATH`. The following
instructions assume you've run `poetry shell` first.
To run the linters:
```bash
mypy fetchartifact tests
pylint fetchartifact tests
```
To auto-format the code (though I recommend configuring your editor to do this
on save):
```bash
isort .
black .
```
To run the tests and generate coverage:
```bash
pytest --cov=fetchartifact
```
Optionally, pass `--cov-report=html` to generate an HTML report, or
`--cov-report=xml` to generate an XML report for your editor.
Some tests require network access. If you need to run the tests in an
environment that cannot access the Android build servers, add
`-m "not requires_network"` to skip those tests. Only a mock service can be
tested without network access.

View File

@@ -0,0 +1,112 @@
#
# Copyright (C) 2023 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
"""A Python interface to https://android.googlesource.com/tools/fetch_artifact/."""
import logging
import urllib
from collections.abc import AsyncIterable
from logging import Logger
from typing import cast
from aiohttp import ClientSession
_DEFAULT_QUERY_URL_BASE = "https://androidbuildinternal.googleapis.com"
def _logger() -> Logger:
return logging.getLogger("fetchartifact")
def _make_download_url(
target: str,
build_id: str,
artifact_name: str,
query_url_base: str,
) -> str:
"""Constructs the download URL.
Args:
target: Name of the build target from which to fetch the artifact.
build_id: ID of the build from which to fetch the artifact.
artifact_name: Name of the artifact to fetch.
Returns:
URL for the given artifact.
"""
# The Android build API does not handle / in artifact names, but urllib.parse.quote
# thinks those are safe by default. We need to escape them.
artifact_name = urllib.parse.quote(artifact_name, safe="")
return (
f"{query_url_base}/android/internal/build/v3/builds/{build_id}/{target}/"
f"attempts/latest/artifacts/{artifact_name}/url"
)
async def fetch_artifact(
target: str,
build_id: str,
artifact_name: str,
session: ClientSession,
query_url_base: str = _DEFAULT_QUERY_URL_BASE,
) -> bytes:
"""Fetches an artifact from the build server.
Args:
target: Name of the build target from which to fetch the artifact.
build_id: ID of the build from which to fetch the artifact.
artifact_name: Name of the artifact to fetch.
session: The aiohttp ClientSession to use. If omitted, one will be created and
destroyed for every call.
query_url_base: The base of the endpoint used for querying download URLs. Uses
the android build service by default, but can be replaced for testing.
Returns:
The bytes of the downloaded artifact.
"""
download_url = _make_download_url(target, build_id, artifact_name, query_url_base)
_logger().debug("Beginning download from %s", download_url)
async with session.get(download_url) as response:
response.raise_for_status()
return await response.read()
async def fetch_artifact_chunked(
target: str,
build_id: str,
artifact_name: str,
session: ClientSession,
chunk_size: int = 16 * 1024 * 1024,
query_url_base: str = _DEFAULT_QUERY_URL_BASE,
) -> AsyncIterable[bytes]:
"""Fetches an artifact from the build server.
Args:
target: Name of the build target from which to fetch the artifact.
build_id: ID of the build from which to fetch the artifact.
artifact_name: Name of the artifact to fetch.
session: The aiohttp ClientSession to use. If omitted, one will be created and
destroyed for every call.
query_url_base: The base of the endpoint used for querying download URLs. Uses
the android build service by default, but can be replaced for testing.
Returns:
Async iterable bytes of the artifact contents.
"""
download_url = _make_download_url(target, build_id, artifact_name, query_url_base)
_logger().debug("Beginning download from %s", download_url)
async with session.get(download_url) as response:
response.raise_for_status()
async for chunk in response.content.iter_chunked(chunk_size):
yield chunk

1142
python-packages/fetchartifact/poetry.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,60 @@
[tool.poetry]
name = "fetchartifact"
version = "0.1.0"
description = "Python library for https://android.googlesource.com/tools/fetch_artifact/."
authors = ["The Android Open Source Project"]
license = "Apache-2.0"
[tool.poetry.dependencies]
python = "^3.10"
aiohttp = "^3.8.4"
[tool.poetry.group.dev.dependencies]
mypy = "^1.2.0"
pylint = "^2.17.2"
black = "^23.3.0"
pytest = "^7.2.2"
pytest-asyncio = "^0.21.0"
isort = "^5.12.0"
pytest-aiohttp = "^1.0.4"
pytest-cov = "^4.0.0"
[tool.coverage.report]
fail_under = 100
[tool.pytest.ini_options]
addopts = "--strict-markers"
asyncio_mode = "auto"
markers = [
"requires_network: marks a test that requires network access"
]
xfail_strict = true
[tool.mypy]
check_untyped_defs = true
disallow_any_generics = true
disallow_any_unimported = true
disallow_subclassing_any = true
disallow_untyped_decorators = true
disallow_untyped_defs = true
follow_imports = "silent"
implicit_reexport = false
namespace_packages = true
no_implicit_optional = true
show_error_codes = true
strict_equality = true
warn_redundant_casts = true
warn_return_any = true
warn_unreachable = true
warn_unused_configs = true
warn_unused_ignores = true
[tool.pylint."MESSAGES CONTROL"]
disable = "duplicate-code,too-many-arguments"
[tool.isort]
profile = "black"
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

View File

@@ -1,4 +1,5 @@
# Copyright (C) 2016 The Android Open Source Project
#
# Copyright (C) 2023 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -11,7 +12,4 @@
# 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.
LOCAL_PATH := $(call my-dir)
include $(call all-makefiles-under, $(LOCAL_PATH))
#

View File

@@ -0,0 +1,101 @@
#
# Copyright (C) 2023 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
"""Tests for fetchartifact."""
from typing import cast
import pytest
from aiohttp import ClientResponseError, ClientSession
from aiohttp.test_utils import TestClient
from aiohttp.web import Application, Request, Response
from fetchartifact import fetch_artifact, fetch_artifact_chunked
TEST_BUILD_ID = "1234"
TEST_TARGET = "linux"
TEST_ARTIFACT_NAME = "output.zip"
TEST_DOWNLOAD_URL = (
f"/android/internal/build/v3/builds/{TEST_BUILD_ID}/{TEST_TARGET}/"
f"attempts/latest/artifacts/{TEST_ARTIFACT_NAME}/url"
)
TEST_RESPONSE = b"Hello, world!"
@pytest.fixture(name="android_ci_client")
async def fixture_android_ci_client(aiohttp_client: type[TestClient]) -> TestClient:
"""Fixture for mocking the Android CI APIs."""
async def download(_request: Request) -> Response:
return Response(text=TEST_RESPONSE.decode("utf-8"))
app = Application()
app.router.add_get(TEST_DOWNLOAD_URL, download)
return await aiohttp_client(app) # type: ignore
async def test_fetch_artifact(android_ci_client: TestClient) -> None:
"""Tests that the download URL is queried."""
assert TEST_RESPONSE == await fetch_artifact(
TEST_TARGET,
TEST_BUILD_ID,
TEST_ARTIFACT_NAME,
cast(ClientSession, android_ci_client),
query_url_base="",
)
async def test_fetch_artifact_chunked(android_ci_client: TestClient) -> None:
"""Tests that the full file contents are downloaded."""
assert [c.encode("utf-8") for c in TEST_RESPONSE.decode("utf-8")] == [
chunk
async for chunk in fetch_artifact_chunked(
TEST_TARGET,
TEST_BUILD_ID,
TEST_ARTIFACT_NAME,
cast(ClientSession, android_ci_client),
chunk_size=1,
query_url_base="",
)
]
async def test_failure_raises(android_ci_client: TestClient) -> None:
"""Tests that fetch failure raises an exception."""
with pytest.raises(ClientResponseError):
await fetch_artifact(
TEST_TARGET,
TEST_BUILD_ID,
TEST_ARTIFACT_NAME,
cast(ClientSession, android_ci_client),
query_url_base="/bad",
)
with pytest.raises(ClientResponseError):
async for _chunk in fetch_artifact_chunked(
TEST_TARGET,
TEST_BUILD_ID,
TEST_ARTIFACT_NAME,
cast(ClientSession, android_ci_client),
query_url_base="/bad",
):
pass
@pytest.mark.requires_network
async def test_real_artifact() -> None:
"""Tests with a real artifact. Requires an internet connection."""
async with ClientSession() as session:
contents = await fetch_artifact("linux", "9945621", "logs/SUCCEEDED", session)
assert contents == b"1681499053\n"

View File

@@ -0,0 +1,24 @@
// Copyright (C) 2023 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package {
default_applicable_licenses: ["Android-Apache-2.0"],
}
python_library_host {
name: "gdbrunner",
srcs: [
"gdbrunner/__init__.py",
],
}

View File

@@ -21,6 +21,7 @@ import argparse
import atexit
import os
import re
import shlex
import subprocess
import sys
import tempfile
@@ -170,11 +171,18 @@ def start_gdbserver(device, gdbserver_local_path, gdbserver_remote_path,
# Push gdbserver to the target.
if gdbserver_local_path is not None:
device.push(gdbserver_local_path, chroot + gdbserver_remote_path)
# If the user here is potentially on Windows, adb cannot inspect execute
# permissions. Since we don't know where the users are, chmod
# gdbserver_remote_path on device regardless.
device.shell(["chmod", "+x", gdbserver_remote_path])
try:
device.push(gdbserver_local_path, chroot + gdbserver_remote_path)
# If the user here is potentially on Windows, adb cannot inspect execute
# permissions. Since we don't know where the users are, chmod
# gdbserver_remote_path on device regardless.
device.shell(["chmod", "+x", gdbserver_remote_path])
except subprocess.CalledProcessError as err:
print("Command failed:")
print(shlex.join(err.cmd))
print("Output:")
print(err.output.decode("utf-8"))
raise
# Run gdbserver.
gdbserver_cmd = [gdbserver_remote_path]

View File

@@ -1,4 +1,5 @@
# Copyright (C) 2011 The Android Open Source Project
#
# Copyright (C) 2023 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -11,13 +12,19 @@
# 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.
#
from setuptools import setup
include $(CLEAR_VARS)
test_module := foo
LOCAL_MODULE := $(test_module)
LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
LOCAL_LICENSE_CONDITIONS := notice
recursive_var := $(recursive_var)
LOCAL_MODULE_TAGS := tags
LOCAL_SRC_FILES := src
include $(BUILD_NATIVE_TEST)
setup(
version='0.0.1',
description='Common helpers of ndk-gdb and gdbclient.',
license='Apache 2.0',
packages=['gdbrunner'],
package_data={'gdbrunner': ['py.typed']},
classifiers=[
'Development Status :: 2 - Pre-Alpha',
'Intended Audience :: Developers',
'License :: OSI Approved :: Apache Software License',
]
)

View File

@@ -0,0 +1,119 @@
package {
default_applicable_licenses: ["Android-Apache-2.0"],
}
android_app {
name: "AconfigDemoActivity",
manifest: "AndroidManifest.xml",
srcs: [
"src/**/*.java"
],
platform_apis: true,
certificate: "platform",
static_libs: [
"ContentLibs",
"dagger2",
"jsr330",
],
jni_libs: [
"libexample_cpp_lib",
],
required: ["libexample_rust_jni"],
plugins: ["dagger2-compiler"],
optimize: {
proguard_flags_files: ["proguard.flags"],
},
}
aconfig_declarations {
name: "aconfig_demo_flags",
package: "com.example.android.aconfig.demo.flags",
srcs: ["aconfig_demo_flags.aconfig"],
}
java_aconfig_library {
name: "aconfig_demo_flags_java_lib",
aconfig_declarations: "aconfig_demo_flags",
}
filegroup {
name: "ContentLibsFile",
srcs: [
"lib/**/*.java",
],
}
java_defaults {
name: "ContentLibsDefault",
sdk_version: "current",
srcs: [
":ContentLibsFile",
],
libs: ["jsr330"],
}
java_library {
name: "ContentLibs",
defaults: ["ContentLibsDefault"],
static_libs: [
"aconfig_demo_flags_java_lib",
],
}
cc_aconfig_library {
name: "aconfig_demo_flags_c_lib",
aconfig_declarations: "aconfig_demo_flags",
}
cc_library {
name: "libexample_cpp_lib",
srcs: ["src/example_cpp_lib.cc"],
double_loadable: true,
cflags: [
"-Wall",
"-Werror",
"-Wno-unused-function",
"-Wno-unused-parameter",
],
header_libs: [
"jni_headers",
],
shared_libs: [
"server_configurable_flags",
],
static_libs: [
"aconfig_demo_flags_c_lib",
],
export_include_dirs: ["src/include"],
}
rust_aconfig_library {
name: "libaconfig_demo_flags_rust",
crate_name: "aconfig_demo_flags_rust",
aconfig_declarations: "aconfig_demo_flags",
}
rust_ffi_shared {
name: "libexample_rust_jni",
crate_name: "example_rust_jni",
srcs: ["src/lib.rs"],
rustlibs: [
"libjni",
"libaconfig_demo_flags_rust",
]
}
// Test setup
// Create test verion of the java flag library
// It needs to use the same aconfig_declarations as
// the production one
java_aconfig_library {
name: "aconfig_demo_flags_java_lib_test",
aconfig_declarations: "aconfig_demo_flags",
// host_supported is set to true here for test running
// one host, in tests/unittests/Android.bp
host_supported: true,
mode: "test",
}

View File

@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2007 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.
-->
<!-- Declare the contents of this Android application. The namespace
attribute brings in the Android platform namespace, and the package
supplies a unique name for the application. When writing your
own application, the package name must be changed from "com.example.*"
to come from a domain that you own or have control over. -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.aconfig.demo">
<uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
<application
android:name="AconfigDemoApplication"
android:label="Hello!">
<activity android:name="AconfigDemoActivity"
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,7 @@
amhk@google.com
dzshen@google.com
jham@google.com
joeo@google.com
opg@google.com
tedbauer@google.com
zhidou@google.com

View File

@@ -0,0 +1,58 @@
package: "com.example.android.aconfig.demo.flags"
flag {
name: "append_injected_content"
namespace: "aconfig_demo_ns"
description: "This flag controls injected content"
bug: "287644619"
}
flag {
name: "append_static_content"
namespace: "aconfig_demo_ns"
description: "This flag controls static content"
bug: "287644619"
}
flag {
name: "awesome_flag_1"
namespace: "test"
description: "A very awesome flag for testing purposes."
bug: "287644619"
}
flag {
name: "awesome_flag_2"
namespace: "test"
description: "Another awesome flag for testing purposes."
bug: "287644619"
}
flag {
name: "fifth_flag"
namespace: "configuration"
description: "The fifth flag, added right after the first three flags."
bug: "287644619"
}
flag {
name: "third_flag"
namespace: "configuration"
description: "This flag controls static content"
bug: "287644619"
}
flag {
name: "read_only_flag"
namespace: "core_experiments_team_internal"
description: "A read only flag for demo"
bug: "298754733"
is_fixed_read_only: true
}
flag {
name: "test_flag_gantry"
namespace: "gantry"
description: "A flag used internally by the aconfig team for some testing. I'll be deleted soon!"
bug: "297503172"
}

View File

@@ -0,0 +1,9 @@
package {
default_applicable_licenses: ["Android-Apache-2.0"],
}
aconfig_declarations {
name: "trunk_stable_workflow_testing",
package: "com.android.trunk_stable_workflow_testing",
srcs: ["trunk_stable_workflow_test.aconfig"],
}

View File

@@ -0,0 +1,8 @@
package: "com.android.trunk_stable_workflow_testing"
flag {
name: "welcome_aboard"
namespace: "core_experiments_team_internal"
description: "Ahoy, raise the first flag of this namespace"
bug: "294537090"
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.aconfig.demo;
import com.example.android.aconfig.demo.flags.FeatureFlags;
import javax.inject.Inject;
public class InjectedContent {
private FeatureFlags featureFlags;
@Inject
public InjectedContent(FeatureFlags featureFlags) {
this.featureFlags = featureFlags;
};
public String getContent() {
StringBuilder sBuffer = new StringBuilder();
if (featureFlags.appendInjectedContent()) {
sBuffer.append("The flag: appendInjectedContent is ON!!\n\n");
} else {
sBuffer.append("The flag: appendInjectedContent is OFF!!\n\n");
}
if (featureFlags.readOnlyFlag()) {
sBuffer.append("The flag: read only flag injected is ON!!\n\n");
} else {
sBuffer.append("The flag: read only flag injected is OFF!!\n\n");
}
return sBuffer.toString();
}
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.aconfig.demo;
import static com.example.android.aconfig.demo.flags.Flags.appendStaticContent;
import static com.example.android.aconfig.demo.flags.Flags.thirdFlag;
import static com.example.android.aconfig.demo.flags.Flags.readOnlyFlag;
public class StaticContent {
public StaticContent() {};
public String getContent() {
StringBuilder sBuffer = new StringBuilder();
if (appendStaticContent()) {
sBuffer.append("The flag: appendStaticContent is ON!!\n\n");
} else {
sBuffer.append("The flag: appendStaticContent is OFF!!\n\n");
}
if (thirdFlag()) {
sBuffer.append("The flag: thirdFlag is ON!!\n\n");
} else {
sBuffer.append("The flag: thirdFlag is OFF!!\n\n");
}
if (readOnlyFlag()) {
sBuffer.append("The flag: read only flag static is ON!!\n\n");
} else {
sBuffer.append("The flag: read only flag static is OFF!!\n\n");
}
return sBuffer.toString();
}
}

View File

@@ -0,0 +1 @@
-keep class **.FakeFeatureFlagsImpl { *; }

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2007 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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:padding="4dip"
android:gravity="center_horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:id="@+id/simpleTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="#444444"
android:textSize="25sp"
android:autoText="true"
android:capitalize="sentences"
android:scrollbars="vertical"
android:textStyle="bold|italic"/>
</LinearLayout>

View File

@@ -0,0 +1,78 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.aconfig.demo;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.WindowManager;
import android.widget.TextView;
import android.text.method.ScrollingMovementMethod;
import com.example.android.aconfig.demo.flags.Flags;
import javax.inject.Inject;
/**
* A minimal "Hello, World!" application.
*/
public class AconfigDemoActivity extends Activity {
@Inject InjectedContent injectedContent;
/**
* Called with the activity is first created.
*/
@Override
public void onCreate(Bundle savedInstanceState) {
((AconfigDemoApplication)getApplicationContext()).appComponent.inject(this);
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView simpleTextView = (TextView) findViewById(R.id.simpleTextView);
simpleTextView.setMovementMethod(new ScrollingMovementMethod());
simpleTextView.setText("Show Java Flags: \n\n");
StaticContent cp = new StaticContent();
simpleTextView.append(cp.getContent());
simpleTextView.append(injectedContent.getContent());
simpleTextView.append("Show C/C++ Flags: \n\n");
simpleTextView.append(printCFlag());
if (Flags.awesomeFlag1()) {
Log.v("AconfigDemoActivity", Flags.FLAG_AWESOME_FLAG_1 + " is on!");
}
if (Flags.awesomeFlag2()) {
Log.v("AconfigDemoActivity", Flags.FLAG_AWESOME_FLAG_2 + " is on!");
}
simpleTextView.append("\n\nShow Rust Flags: \n\n");
simpleTextView.append(printRustFlag());
}
public native String printCFlag();
public native String printRustFlag();
static {
System.loadLibrary("example_cpp_lib");
System.loadLibrary("example_rust_jni");
}
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.aconfig.demo;
import android.app.Application;
import com.example.android.aconfig.demo.dagger.ApplicationComponent;
import com.example.android.aconfig.demo.dagger.DaggerApplicationComponent;
/**
* A minimal "Hello, World!" application.
*/
public class AconfigDemoApplication extends Application {
ApplicationComponent appComponent = DaggerApplicationComponent.create();
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.aconfig.demo.dagger;
import com.example.android.aconfig.demo.flags.FeatureFlags;
import com.example.android.aconfig.demo.flags.FeatureFlagsImpl;
import dagger.Module;
import dagger.Provides;
@Module
public class AconfigDemoFlagModule {
@Provides
static FeatureFlags provideFeatureFlags() {
return new FeatureFlagsImpl();
}
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.aconfig.demo.dagger;
import com.example.android.aconfig.demo.AconfigDemoActivity;
import dagger.Component;
@Component(modules = {AconfigDemoFlagModule.class})
public interface ApplicationComponent {
void inject(AconfigDemoActivity aconfigDemoActivity);
}

View File

@@ -0,0 +1,34 @@
#include "example_cpp_lib.h"
#include <string>
#include <com_example_android_aconfig_demo_flags.h>
namespace demo_flags = com::example::android::aconfig::demo::flags;
// use static methods interface
static std::string get_flag_via_static_interface() {
return std::string("flag value : ") +
(demo_flags::append_static_content() ? "true" : "false");
}
// use flag provider for injection interface
static std::string get_flag_via_injection_interface(
demo_flags::flag_provider_interface* provider) {
return std::string("flag value : ") +
((provider->append_injected_content()) ? "true" : "false");
}
jstring Java_com_example_android_aconfig_demo_AconfigDemoActivity_printCFlag(
JNIEnv* env,
jobject thiz) {
auto result = std::string("flag name : append_static_content\n");
result += "use pattern : static method\n";
result += get_flag_via_static_interface();
result += "\n\n";
result += "flag name : append_injected_content\n";
result += "use pattern : injection\n";
result += get_flag_via_injection_interface(demo_flags::provider_.get());
return env->NewStringUTF(result.c_str());
}

View File

@@ -0,0 +1,7 @@
#pragma once
#include <jni.h>
extern "C" jstring Java_com_example_android_aconfig_demo_AconfigDemoActivity_printCFlag(
JNIEnv* env,
jobject thiz);

View File

@@ -0,0 +1,46 @@
//! example rust crate to be used in AconfigDemoActivity app
use jni::objects::JClass;
use jni::sys::jstring;
use jni::JNIEnv;
/// get flag value via static interface
pub fn get_flag_via_static_interface() -> String {
format!(
"flag value: {}",
if aconfig_demo_flags_rust::append_static_content() { "true" } else { "false" }
)
}
/// get flag value via injection
pub fn get_flag_via_injection_interface(
provider: &aconfig_demo_flags_rust::FlagProvider,
) -> String {
format!("flag value: {}", if provider.append_injected_content() { "true" } else { "false" })
}
/// printRustFlag function
#[no_mangle]
#[allow(unused)]
pub extern "system" fn Java_com_example_android_aconfig_demo_AconfigDemoActivity_printRustFlag<
'local,
>(
mut env: JNIEnv<'local>,
class: JClass<'local>,
) -> jstring {
let mut result = String::new();
result.push_str("flag name : append_static_content\n");
result.push_str("use pattern : static method\n");
result.push_str(&get_flag_via_static_interface());
result.push_str("\n\n");
result.push_str("flag name : append_injected_content\n");
result.push_str("use pattern : injection\n");
result.push_str(&get_flag_via_injection_interface(&aconfig_demo_flags_rust::PROVIDER));
let output = env.new_string(result).expect("Couldn't create java string!");
output.into_raw()
}

View File

@@ -0,0 +1,18 @@
package {
default_applicable_licenses: ["Android-Apache-2.0"],
}
android_test {
name: "AconfigDemo_ContentLibs_Test",
srcs: ["src/**/*.java"],
certificate: "platform",
static_libs: [
"junit",
"mockito-target-minus-junit4",
"androidx.test.runner",
"flag-junit",
"platform-test-annotations",
],
manifest: "AndroidManifest.xml",
instrumentation_for: "AconfigDemoActivity",
}

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2008 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"
package="com.example.android.aconfig.demo.tests">
<uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
<!-- We add an application tag here just so that we can indicate that
this package needs to link against the android.test library,
which is needed when building test cases. -->
<application>
<uses-library android:name="android.test.runner" />
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="com.example.android.aconfig.demo"
android:label="AconfigDemoActivity sample tests">
</instrumentation>
</manifest>

View File

@@ -0,0 +1 @@
tested.project.dir=..

View File

@@ -0,0 +1,71 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.aconfig.demo;
import android.platform.test.annotations.RequiresFlagsDisabled;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import com.example.android.aconfig.demo.flags.Flags;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Tests for how combination of flags states effects execution */
@RunWith(JUnit4.class)
public final class FlagStateComboTests {
@Rule
public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
@Test
@RequiresFlagsEnabled(Flags.FLAG_AWESOME_FLAG_1)
public void requires_f1on_pass_or_skip() {}
@Test
@RequiresFlagsDisabled(Flags.FLAG_AWESOME_FLAG_2)
public void requires_f2off_pass_or_skip() {}
@Test
@RequiresFlagsEnabled(Flags.FLAG_AWESOME_FLAG_1)
public void requires_f1on_throw_or_skip() {
throw new RuntimeException("This exception is expected if "
+ Flags.FLAG_AWESOME_FLAG_1 + " is enabled");
}
@Test
@RequiresFlagsDisabled(Flags.FLAG_AWESOME_FLAG_2)
public void requires_f2off_throw_or_skip() {
throw new RuntimeException("This exception is expected if "
+ Flags.FLAG_AWESOME_FLAG_2 + " is disabled");
}
@Test
@RequiresFlagsEnabled({Flags.FLAG_AWESOME_FLAG_1, Flags.FLAG_AWESOME_FLAG_2})
public void requires_f1on_f2on_pass_or_skip() {}
@Test
@RequiresFlagsEnabled(Flags.FLAG_AWESOME_FLAG_1)
@RequiresFlagsDisabled(Flags.FLAG_AWESOME_FLAG_2)
public void requires_f1on_f2off_throw_or_skip() {
throw new RuntimeException("This exception is expected if "
+ Flags.FLAG_AWESOME_FLAG_1 + " is enabled and "
+ Flags.FLAG_AWESOME_FLAG_2 + " is disabled");
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.aconfig.demo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.mock;
import com.example.android.aconfig.demo.flags.FeatureFlags;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@RunWith(JUnit4.class)
public final class InjectedContentTests {
@Test
public void testInjectedContentFlagOn() throws Exception {
FeatureFlags fakeFeatureFlag = mock(FeatureFlags.class);
when(fakeFeatureFlag.appendInjectedContent()).thenReturn(true);
InjectedContent injectedContent = new InjectedContent(fakeFeatureFlag);
StringBuilder expected = new StringBuilder();
expected.append("The flag: appendInjectedContent is ON!!\n\n");
assertEquals("Get appendInjectedContent", expected.toString(), injectedContent.getContent());
}
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.aconfig.demo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import com.example.android.aconfig.demo.flags.Flags;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@RunWith(JUnit4.class)
public final class StaticContentTests {
@Test
public void testFlag() {
assertFalse(Flags.appendStaticContent());
}
}

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- This test config file is auto-generated. -->
<configuration description="Runs AconfigDemoUnitTests.">
<target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
<option name="run-command" value="pm uninstall com.example.android.aconfig.demo" />
<option name="run-command" value="pm uninstall com.example.android.aconfig.demo.tests" />
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="AconfigDemoUnitTests.apk" />
<option name="test-file-name" value="AconfigDemoActivity.apk" />
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="com.example.android.aconfig.demo.tests" />
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
</test>
</configuration>

View File

@@ -0,0 +1,27 @@
java_library_host {
name: "ContentLibsHost",
srcs: [
":ContentLibsFile",
],
static_libs: [
"aconfig_demo_flags_java_lib_test",
],
libs: ["jsr330"],
}
android_test {
name: "AconfigDemoUnitTests",
srcs: ["*.java"],
certificate: "platform",
static_libs: [
"junit",
"androidx.test.runner",
"flag-junit-base",
"platform-test-annotations",
"aconfig_demo_flags_java_lib",
],
manifest: "AndroidManifest.xml",
test_config: "AconfigDemoUnitTests.xml",
data: [":AconfigDemoActivity"],
instrumentation_for: "AconfigDemoActivity",
}

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2008 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"
package="com.example.android.aconfig.demo.tests">
<uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
<!-- We add an application tag here just so that we can indicate that
this package needs to link against the android.test library,
which is needed when building test cases. -->
<application>
<uses-library android:name="android.test.runner" />
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="com.example.android.aconfig.demo"
android:label="AconfigDemoActivity sample tests">
</instrumentation>
</manifest>

View File

@@ -0,0 +1,76 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.aconfig.demo;
import static org.junit.Assert.assertEquals;
import android.platform.test.flag.junit.SetFlagsRule;
import com.example.android.aconfig.demo.flags.Flags;
import org.junit.Assume;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@RunWith(Parameterized.class)
public final class StaticContentUnitTests {
@Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
@Parameterized.Parameters(name = "isInitWithDefault={0}")
public static Object[] data() {
return new Boolean[] {false, true};
}
public StaticContentUnitTests(boolean isInitWithDefault) {
mIsInitWithDefault = isInitWithDefault;
if (isInitWithDefault) {
mSetFlagsRule.initAllFlagsToReleaseConfigDefault();
}
}
private boolean mIsInitWithDefault;
@Test
public void staticContent_enable_staticFlag_disable_thirdFlag() {
Assume.assumeTrue(!mIsInitWithDefault);
mSetFlagsRule.enableFlags(Flags.FLAG_APPEND_STATIC_CONTENT);
mSetFlagsRule.disableFlags(Flags.FLAG_THIRD_FLAG);
mSetFlagsRule.disableFlags(Flags.FLAG_READ_ONLY_FLAG);
StaticContent statiContent = new StaticContent();
String ret = statiContent.getContent();
StringBuilder expected = new StringBuilder();
expected.append("The flag: appendStaticContent is ON!!\n\n");
expected.append("The flag: thirdFlag is OFF!!\n\n");
expected.append("The flag: read only flag static is OFF!!\n\n");
assertEquals("Expected message", expected.toString(), ret);
}
@Test
public void staticContent_enable_thirdFlag_with_default() {
Assume.assumeTrue(mIsInitWithDefault);
mSetFlagsRule.enableFlags(Flags.FLAG_THIRD_FLAG);
StaticContent statiContent = new StaticContent();
String ret = statiContent.getContent();
StringBuilder expected = new StringBuilder();
expected.append("The flag: appendStaticContent is OFF!!\n\n");
expected.append("The flag: thirdFlag is ON!!\n\n");
expected.append("The flag: read only flag static is OFF!!\n\n");
assertEquals("Expected message", expected.toString(), ret);
}
}

View File

@@ -42,7 +42,9 @@ public class JobWorkServiceActivity extends Activity {
mJobScheduler = (JobScheduler)getSystemService(JOB_SCHEDULER_SERVICE);
mJobInfo = new JobInfo.Builder(R.string.job_service_created,
new ComponentName(this, JobWorkService.class)).setOverrideDeadline(0).build();
new ComponentName(this, JobWorkService.class))
.setRequiresBatteryNotLow(true)
.build();
setContentView(R.layout.job_work_service_activity);

View File

@@ -5,7 +5,7 @@ package {
android_app {
name: "AutofillKeyboard",
srcs: ["**/*.java"],
min_sdk_version: "29",
min_sdk_version: "30",
target_sdk_version: "30",
sdk_version: "current",
static_libs: [

View File

@@ -1,404 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<issues format="5" by="lint 7.2.0-dev" client="cli" variant="all" version="4.1.0">
<issue
id="NewApi"
message="Call requires API level 30 (current min is 29): `setZOrderedOnTop`">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="82"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 29): `setZOrderedOnTop`">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="88"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 29): `android.view.inputmethod.InlineSuggestionsResponse#getInlineSuggestions`">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="151"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 29): `newStylesBuilder`">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="229"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 29): `newStyleBuilder`">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="230"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 29): `Builder`">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="232"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 29): `setBackground`">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="233"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 29): `setPadding`">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="235"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 29): `build`">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="236"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 29): `Builder`">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="238"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 29): `setBackground`">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="239"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 29): `setPadding`">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="241"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 29): `build`">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="242"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 29): `Builder`">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="243"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 29): `build`">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="243"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 29): `setLayoutMargin`">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="243"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 29): `Builder`">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="245"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 29): `setLayoutMargin`">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="246"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 29): `setTextColor`">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="247"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 29): `setTextColor`">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="247"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 29): `setTextSize`">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="248"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 29): `build`">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="249"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 29): `Builder`">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="251"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 29): `setLayoutMargin`">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="252"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 29): `setTextColor`">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="253"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 29): `setTextColor`">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="253"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 29): `setTextSize`">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="254"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 29): `build`">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="255"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 29): `Builder`">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="256"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 29): `build`">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="256"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 29): `setLayoutMargin`">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="256"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 29): `addStyle`">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="258"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 29): `build`">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="259"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 29): `new android.widget.inline.InlinePresentationSpec.Builder`">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="262"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 29): `android.widget.inline.InlinePresentationSpec.Builder#build`">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="263"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 29): `android.widget.inline.InlinePresentationSpec.Builder#setStyle`">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="263"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 29): `new android.widget.inline.InlinePresentationSpec.Builder`">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="264"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 29): `android.widget.inline.InlinePresentationSpec.Builder#build`">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="265"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 29): `android.widget.inline.InlinePresentationSpec.Builder#setStyle`">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="265"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 29): `new android.view.inputmethod.InlineSuggestionsRequest.Builder`">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="267"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 29): `android.view.inputmethod.InlineSuggestionsRequest.Builder#setMaxSuggestionCount`">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="268"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 29): `android.view.inputmethod.InlineSuggestionsRequest.Builder#build`">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="269"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 29): `android.view.inputmethod.InlineSuggestionsResponse#getInlineSuggestions`">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="284"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 29): `setBackgroundColor`">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="301"/>
</issue>
<issue
id="NewApi"
message="Cast from `InlineContentView` to `View` requires API level 30 (current min is 29)">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="312"/>
</issue>
<issue
id="NewApi"
message="Cast from `InlineContentView` to `View` requires API level 30 (current min is 29)">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="314"/>
</issue>
<issue
id="NewApi"
message="Cast from `InlineContentView` to `View` requires API level 30 (current min is 29)">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="317"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 29): `android.view.inputmethod.InlineSuggestion#inflate`">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="363"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 29): `android.view.inputmethod.InlineSuggestion#getInfo`">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="374"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 29): `android.view.inputmethod.InlineSuggestionInfo#isPinned`">
<location
file="development/samples/AutofillKeyboard/src/com/example/android/autofillkeyboard/AutofillImeService.java"
line="374"/>
</issue>
</issues>

View File

@@ -0,0 +1,10 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id 'com.android.application' version '8.0.0' apply false
id 'com.android.library' version '8.0.0' apply false
id 'org.jetbrains.kotlin.android' version '1.8.20-RC' apply false
}
task clean(type: Delete) {
delete rootProject.buildDir
}

View File

@@ -0,0 +1,27 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app"s APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
# Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official
# Enables namespacing of each library's R class so that its R class includes only the
# resources declared in the library itself and none from the library's dependencies,
# thereby reducing the size of the R class for that library
android.nonTransitiveRClass=true
org.gradle.parallel=true
android.defaults.buildfeatures.buildconfig=true
android.nonFinalResIds=false

Binary file not shown.

View File

@@ -0,0 +1,6 @@
#Thu May 26 13:09:53 JST 2022
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME

185
samples/NsdManagerSample/gradlew vendored Executable file
View File

@@ -0,0 +1,185 @@
#!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# 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
#
# https://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.
#
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
exec "$JAVACMD" "$@"

89
samples/NsdManagerSample/gradlew.bat vendored Normal file
View File

@@ -0,0 +1,89 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@@ -0,0 +1,17 @@
pluginManagement {
repositories {
gradlePluginPortal()
google()
mavenCentral()
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
}
}
rootProject.name = "TestAdvertiseService"
include ':testadvertiseservice'
include ':testdiscoverservice'

View File

@@ -0,0 +1,45 @@
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
}
android {
compileSdkPreview "UpsideDownCake"
defaultConfig {
applicationId "com.example.testadvertiseservice"
minSdk 31
targetSdk 33
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
namespace 'com.example.testadvertiseservice'
}
dependencies {
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.3.0'
implementation 'com.google.android.material:material:1.4.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'androidx.core:core-ktx:+'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}

View File

@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.TestAdvertiseService"
tools:targetApi="31">
<activity
android:name=".AdvertiseActivity"
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,86 @@
/*
* Copyright 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.testadvertiseservice
import android.net.nsd.NsdManager
import android.net.nsd.NsdServiceInfo
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.text.TextUtils
import android.util.Log
import android.widget.TextView
private val TAG = AdvertiseActivity::class.simpleName
class AdvertiseActivity : AppCompatActivity() {
private val nsdManager by lazy { getSystemService(NsdManager::class.java) }
private val lblLog by lazy { findViewById<TextView>(R.id.lblMainActivity) }
private val log = mutableListOf<String>()
private var listener: RegistrationListener? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
override fun onStart() {
super.onStart()
val service = NsdServiceInfo().apply {
serviceName = "test_service"
serviceType = "_nmt._tcp"
port = 10234
}
listener = RegistrationListener()
log("Registering service")
nsdManager.registerService(service, NsdManager.PROTOCOL_DNS_SD, listener)
}
override fun onStop() {
super.onStop()
listener?.let { nsdManager.unregisterService(it) }
listener = null
}
private fun log(msg: String) {
runOnUiThread {
log.add(msg)
Log.i(TAG, msg)
lblLog.text = TextUtils.join("\n", log)
}
}
inner class RegistrationListener : NsdManager.RegistrationListener {
override fun onRegistrationFailed(serviceType: NsdServiceInfo?, errorCode: Int) {
log("Registration failed for type $serviceType, error $errorCode")
}
override fun onUnregistrationFailed(serviceType: NsdServiceInfo?, errorCode: Int) {
log("Unregistration failed for type $serviceType, error $errorCode")
}
override fun onServiceRegistered(serviceInfo: NsdServiceInfo?) {
log("Service registered for type $serviceInfo")
}
override fun onServiceUnregistered(serviceType: NsdServiceInfo?) {
log("Service unregistered for type $serviceType")
}
}
}

View File

@@ -0,0 +1,45 @@
<!--
Copyright 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>

View File

@@ -0,0 +1,185 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>

View File

@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".AdvertiseActivity">
<ScrollView
android:layout_width="0dp"
android:layout_height="0dp"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/lblMainActivity"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Hello\nWorld!"
android:layout_margin="8dp" />
</ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -0,0 +1,31 @@
<!--
Copyright 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.TestAdvertiseService" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_200</item>
<item name="colorPrimaryVariant">@color/purple_700</item>
<item name="colorOnPrimary">@color/black</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_200</item>
<item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. -->
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
<!-- Customize your theme here. -->
</style>
</resources>

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<color name="purple_200">#FFBB86FC</color>
<color name="purple_500">#FF6200EE</color>
<color name="purple_700">#FF3700B3</color>
<color name="teal_200">#FF03DAC5</color>
<color name="teal_700">#FF018786</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
</resources>

View File

@@ -0,0 +1,18 @@
<!--
Copyright 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="app_name">TestAdvertiseService</string>
</resources>

View File

@@ -0,0 +1,31 @@
<!--
Copyright 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.TestAdvertiseService" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_500</item>
<item name="colorPrimaryVariant">@color/purple_700</item>
<item name="colorOnPrimary">@color/white</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_700</item>
<item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. -->
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
<!-- Customize your theme here. -->
</style>
</resources>

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!--
Sample backup rules file; uncomment and customize as necessary.
See https://developer.android.com/guide/topics/data/autobackup
for details.
Note: This file is ignored for devices older that API 31
See https://developer.android.com/about/versions/12/backup-restore
-->
<full-backup-content>
<!--
<include domain="sharedpref" path="."/>
<exclude domain="sharedpref" path="device.xml"/>
-->
</full-backup-content>

Some files were not shown because too many files have changed in this diff Show More