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:
@@ -19,6 +19,8 @@ package {
|
||||
|
||||
filegroup {
|
||||
name: "development_docs",
|
||||
visibility: ["//visibility:private"],
|
||||
visibility: [
|
||||
"//art/test:__subpackages__",
|
||||
],
|
||||
srcs: ["docs/**/*"],
|
||||
}
|
||||
|
||||
@@ -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}
|
||||
@@ -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">
|
||||
|
||||
39
apps/Development/res/layout/http_engine_activity.xml
Normal file
39
apps/Development/res/layout/http_engine_activity.xml
Normal 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>
|
||||
|
||||
56
apps/Development/res/layout/http_engine_dialog.xml
Normal file
56
apps/Development/res/layout/http_engine_dialog.xml
Normal 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>
|
||||
|
||||
20
apps/Development/res/values/dimens.xml
Normal file
20
apps/Development/res/values/dimens.xml
Normal 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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
},
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -183,14 +183,15 @@ public class MainActivity extends Activity {
|
||||
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;
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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; -*-
|
||||
@@ -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 :=
|
||||
|
||||
@@ -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",
|
||||
],
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
1
gki/kmi_abi_chk/sym-5.15/Module.symvers
Symbolic link
1
gki/kmi_abi_chk/sym-5.15/Module.symvers
Symbolic link
@@ -0,0 +1 @@
|
||||
Module.symvers-10342779
|
||||
5764
gki/kmi_abi_chk/sym-5.15/Module.symvers-10342779
Normal file
5764
gki/kmi_abi_chk/sym-5.15/Module.symvers-10342779
Normal file
File diff suppressed because it is too large
Load Diff
1
gki/kmi_abi_chk/sym-6.1/Module.symvers
Symbolic link
1
gki/kmi_abi_chk/sym-6.1/Module.symvers
Symbolic link
@@ -0,0 +1 @@
|
||||
Module.symvers-10816536
|
||||
6663
gki/kmi_abi_chk/sym-6.1/Module.symvers-10342778
Normal file
6663
gki/kmi_abi_chk/sym-6.1/Module.symvers-10342778
Normal file
File diff suppressed because it is too large
Load Diff
6781
gki/kmi_abi_chk/sym-6.1/Module.symvers-10521792
Normal file
6781
gki/kmi_abi_chk/sym-6.1/Module.symvers-10521792
Normal file
File diff suppressed because it is too large
Load Diff
6875
gki/kmi_abi_chk/sym-6.1/Module.symvers-10672300
Normal file
6875
gki/kmi_abi_chk/sym-6.1/Module.symvers-10672300
Normal file
File diff suppressed because it is too large
Load Diff
7068
gki/kmi_abi_chk/sym-6.1/Module.symvers-10816536
Normal file
7068
gki/kmi_abi_chk/sym-6.1/Module.symvers-10816536
Normal file
File diff suppressed because it is too large
Load Diff
177
gsi/repack_super_image/mix_ssi_with_device_image.py
Executable file
177
gsi/repack_super_image/mix_ssi_with_device_image.py
Executable 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()
|
||||
@@ -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__":
|
||||
|
||||
@@ -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)
|
||||
@@ -1,16 +1,6 @@
|
||||
<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>
|
||||
<code_scheme name="AndroidStyle" version="173">
|
||||
<option name="RIGHT_MARGIN" value="100" />
|
||||
<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" />
|
||||
@@ -33,6 +23,8 @@
|
||||
<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" />
|
||||
@@ -55,10 +47,14 @@
|
||||
<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" />
|
||||
@@ -70,42 +66,28 @@
|
||||
<package name="" withSubpackages="true" static="false" />
|
||||
</value>
|
||||
</option>
|
||||
<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>
|
||||
<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>
|
||||
@@ -1,4 +0,0 @@
|
||||
inseob@google.com
|
||||
jeongik@google.com
|
||||
justinyun@google.com
|
||||
kiyoungkim@google.com
|
||||
@@ -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
|
||||
@@ -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()
|
||||
1
python-packages/fetchartifact/OWNERS
Normal file
1
python-packages/fetchartifact/OWNERS
Normal file
@@ -0,0 +1 @@
|
||||
danalbert@google.com
|
||||
64
python-packages/fetchartifact/README.md
Normal file
64
python-packages/fetchartifact/README.md
Normal 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.
|
||||
112
python-packages/fetchartifact/fetchartifact/__init__.py
Normal file
112
python-packages/fetchartifact/fetchartifact/__init__.py
Normal 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
1142
python-packages/fetchartifact/poetry.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
60
python-packages/fetchartifact/pyproject.toml
Normal file
60
python-packages/fetchartifact/pyproject.toml
Normal 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"
|
||||
@@ -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))
|
||||
#
|
||||
101
python-packages/fetchartifact/tests/test_fetchartifact.py
Normal file
101
python-packages/fetchartifact/tests/test_fetchartifact.py
Normal 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"
|
||||
24
python-packages/gdbrunner/Android.bp
Normal file
24
python-packages/gdbrunner/Android.bp
Normal 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",
|
||||
],
|
||||
}
|
||||
@@ -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:
|
||||
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]
|
||||
0
python-packages/gdbrunner/gdbrunner/py.typed
Normal file
0
python-packages/gdbrunner/gdbrunner/py.typed
Normal 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',
|
||||
]
|
||||
)
|
||||
119
samples/AconfigDemo/Android.bp
Normal file
119
samples/AconfigDemo/Android.bp
Normal 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",
|
||||
}
|
||||
36
samples/AconfigDemo/AndroidManifest.xml
Normal file
36
samples/AconfigDemo/AndroidManifest.xml
Normal 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>
|
||||
7
samples/AconfigDemo/OWNERS
Normal file
7
samples/AconfigDemo/OWNERS
Normal 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
|
||||
58
samples/AconfigDemo/aconfig_demo_flags.aconfig
Normal file
58
samples/AconfigDemo/aconfig_demo_flags.aconfig
Normal 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"
|
||||
}
|
||||
9
samples/AconfigDemo/internal/Android.bp
Normal file
9
samples/AconfigDemo/internal/Android.bp
Normal 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"],
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
1
samples/AconfigDemo/proguard.flags
Normal file
1
samples/AconfigDemo/proguard.flags
Normal file
@@ -0,0 +1 @@
|
||||
-keep class **.FakeFeatureFlagsImpl { *; }
|
||||
33
samples/AconfigDemo/res/layout/main.xml
Normal file
33
samples/AconfigDemo/res/layout/main.xml
Normal 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>
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
34
samples/AconfigDemo/src/example_cpp_lib.cc
Normal file
34
samples/AconfigDemo/src/example_cpp_lib.cc
Normal 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());
|
||||
}
|
||||
7
samples/AconfigDemo/src/include/example_cpp_lib.h
Normal file
7
samples/AconfigDemo/src/include/example_cpp_lib.h
Normal 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);
|
||||
46
samples/AconfigDemo/src/lib.rs
Normal file
46
samples/AconfigDemo/src/lib.rs
Normal 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()
|
||||
}
|
||||
18
samples/AconfigDemo/tests/Android.bp
Normal file
18
samples/AconfigDemo/tests/Android.bp
Normal 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",
|
||||
}
|
||||
32
samples/AconfigDemo/tests/AndroidManifest.xml
Normal file
32
samples/AconfigDemo/tests/AndroidManifest.xml
Normal 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>
|
||||
1
samples/AconfigDemo/tests/build.properties
Normal file
1
samples/AconfigDemo/tests/build.properties
Normal file
@@ -0,0 +1 @@
|
||||
tested.project.dir=..
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
33
samples/AconfigDemo/tests/unittests/AconfigDemoUnitTests.xml
Normal file
33
samples/AconfigDemo/tests/unittests/AconfigDemoUnitTests.xml
Normal 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>
|
||||
27
samples/AconfigDemo/tests/unittests/Android.bp
Normal file
27
samples/AconfigDemo/tests/unittests/Android.bp
Normal 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",
|
||||
}
|
||||
32
samples/AconfigDemo/tests/unittests/AndroidManifest.xml
Normal file
32
samples/AconfigDemo/tests/unittests/AndroidManifest.xml
Normal 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>
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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: [
|
||||
|
||||
@@ -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>
|
||||
10
samples/NsdManagerSample/build.gradle
Normal file
10
samples/NsdManagerSample/build.gradle
Normal 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
|
||||
}
|
||||
27
samples/NsdManagerSample/gradle.properties
Normal file
27
samples/NsdManagerSample/gradle.properties
Normal 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
|
||||
BIN
samples/NsdManagerSample/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
samples/NsdManagerSample/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
6
samples/NsdManagerSample/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
6
samples/NsdManagerSample/gradle/wrapper/gradle-wrapper.properties
vendored
Normal 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
185
samples/NsdManagerSample/gradlew
vendored
Executable 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
89
samples/NsdManagerSample/gradlew.bat
vendored
Normal 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
|
||||
17
samples/NsdManagerSample/settings.gradle
Normal file
17
samples/NsdManagerSample/settings.gradle
Normal 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'
|
||||
45
samples/NsdManagerSample/testadvertiseservice/build.gradle
Normal file
45
samples/NsdManagerSample/testadvertiseservice/build.gradle
Normal 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'
|
||||
}
|
||||
21
samples/NsdManagerSample/testadvertiseservice/proguard-rules.pro
vendored
Normal file
21
samples/NsdManagerSample/testadvertiseservice/proguard-rules.pro
vendored
Normal 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
|
||||
@@ -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>
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -0,0 +1,35 @@
|
||||
<?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 data extraction rules file; uncomment and customize as necessary.
|
||||
See https://developer.android.com/about/versions/12/backup-restore#xml-changes
|
||||
for details.
|
||||
-->
|
||||
<data-extraction-rules>
|
||||
<cloud-backup>
|
||||
<!-- TODO: Use <include> and <exclude> to control what is backed up.
|
||||
<include .../>
|
||||
<exclude .../>
|
||||
-->
|
||||
</cloud-backup>
|
||||
<!--
|
||||
<device-transfer>
|
||||
<include .../>
|
||||
<exclude .../>
|
||||
</device-transfer>
|
||||
-->
|
||||
</data-extraction-rules>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user