diff options
78 files changed, 2054 insertions, 482 deletions
diff --git a/ApiDocs.bp b/ApiDocs.bp index 39f055b578ab..a542c5cf245c 100644 --- a/ApiDocs.bp +++ b/ApiDocs.bp @@ -134,11 +134,7 @@ droidstubs { defaults: ["android-non-updatable-doc-stubs-defaults"], srcs: [":all-modules-public-stubs-source"], args: metalava_framework_docs_args, - api_levels_annotations_enabled: true, - api_levels_annotations_dirs: [ - "sdk-dir", - "api-versions-jars-dir", - ], + api_levels_module: "api_versions_public", aidl: { include_dirs: [ "packages/modules/Connectivity/framework/aidl-export", diff --git a/apct-tests/perftests/core/src/android/libcore/ZipFilePerfTest.java b/apct-tests/perftests/core/src/android/libcore/ZipFilePerfTest.java index 517e3ce39d7e..31c92ba5e207 100644 --- a/apct-tests/perftests/core/src/android/libcore/ZipFilePerfTest.java +++ b/apct-tests/perftests/core/src/android/libcore/ZipFilePerfTest.java @@ -70,6 +70,9 @@ public class ZipFilePerfTest { BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { ZipFile zf = new ZipFile(mFile); + state.pauseTiming(); + zf.close(); + state.resumeTiming(); } } diff --git a/apct-tests/perftests/core/src/android/libcore/regression/ExpensiveObjectsPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/ExpensiveObjectsPerfTest.java index 32117dcd1d9f..03c9d43d3258 100644 --- a/apct-tests/perftests/core/src/android/libcore/regression/ExpensiveObjectsPerfTest.java +++ b/apct-tests/perftests/core/src/android/libcore/regression/ExpensiveObjectsPerfTest.java @@ -141,15 +141,6 @@ public class ExpensiveObjectsPerfTest { } @Test - public void timeNumberFormatTrivialFormatLong() { - NumberFormat nf = NumberFormat.getInstance(Locale.US); - BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); - while (state.keepRunning()) { - nf.format(1024L); - } - } - - @Test public void timeLongToString() { BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { diff --git a/apct-tests/perftests/core/src/android/libcore/regression/HostnameVerifierPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/HostnameVerifierPerfTest.java deleted file mode 100644 index f2b7fdfdc1ca..000000000000 --- a/apct-tests/perftests/core/src/android/libcore/regression/HostnameVerifierPerfTest.java +++ /dev/null @@ -1,192 +0,0 @@ -/* - * 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. - */ - -package android.libcore.regression; - -import android.perftests.utils.BenchmarkState; -import android.perftests.utils.PerfStatusReporter; -import android.test.suitebuilder.annotation.LargeTest; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; - -import java.io.ByteArrayInputStream; -import java.net.URL; -import java.security.Principal; -import java.security.cert.Certificate; -import java.security.cert.CertificateFactory; -import java.util.Arrays; -import java.util.Collection; - -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLSession; -import javax.net.ssl.SSLSessionContext; - -/** - * This benchmark makes a real HTTP connection to a handful of hosts and - * captures the served certificates as a byte array. It then verifies each - * certificate in the benchmark loop, being careful to convert from the - * byte[] to the certificate each time. Otherwise the certificate class - * caches previous results which skews the results of the benchmark: In practice - * each certificate instance is verified once and then released. - */ -@RunWith(Parameterized.class) -@LargeTest -public final class HostnameVerifierPerfTest { - @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); - - @Parameters(name = "mHost({0})") - public static Collection<Object[]> data() { - return Arrays.asList( - new Object[][] { - {"m.google.com"}, - {"www.google.com"}, - {"www.amazon.com"}, - {"www.ubs.com"} - }); - } - - @Parameterized.Parameter(0) - public String mHost; - - - private String mHostname; - private HostnameVerifier mHostnameVerifier; - private byte[][] mEncodedCertificates; - - @Before - public void setUp() throws Exception { - URL url = new URL("https", mHost, "/"); - mHostnameVerifier = HttpsURLConnection.getDefaultHostnameVerifier(); - HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(); - connection.setHostnameVerifier(new HostnameVerifier() { - public boolean verify(String mHostname, SSLSession sslSession) { - try { - mEncodedCertificates = certificatesToBytes(sslSession.getPeerCertificates()); - } catch (Exception e) { - throw new RuntimeException(e); - } - HostnameVerifierPerfTest.this.mHostname = mHostname; - return true; - } - }); - connection.getInputStream(); - connection.disconnect(); - } - - @Test - public void timeVerify() throws Exception { - BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); - while (state.keepRunning()) { - final Certificate[] certificates = bytesToCertificates(mEncodedCertificates); - FakeSSLSession sslSession = new FakeSSLSession() { - @Override public Certificate[] getPeerCertificates() { - return certificates; - } - }; - mHostnameVerifier.verify(mHostname, sslSession); - } - } - - private byte[][] certificatesToBytes(Certificate[] certificates) throws Exception { - byte[][] result = new byte[certificates.length][]; - for (int i = 0, certificatesLength = certificates.length; i < certificatesLength; i++) { - result[i] = certificates[i].getEncoded(); - } - return result; - } - - private Certificate[] bytesToCertificates(byte[][] encodedCertificates) throws Exception { - CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); - Certificate[] result = new Certificate[encodedCertificates.length]; - for (int i = 0; i < encodedCertificates.length; i++) { - result[i] = certificateFactory.generateCertificate( - new ByteArrayInputStream(encodedCertificates[i])); - } - return result; - } - - private static class FakeSSLSession implements SSLSession { - public int getApplicationBufferSize() { - throw new UnsupportedOperationException(); - } - public String getCipherSuite() { - throw new UnsupportedOperationException(); - } - public long getCreationTime() { - throw new UnsupportedOperationException(); - } - public byte[] getId() { - throw new UnsupportedOperationException(); - } - public long getLastAccessedTime() { - throw new UnsupportedOperationException(); - } - public Certificate[] getLocalCertificates() { - throw new UnsupportedOperationException(); - } - public Principal getLocalPrincipal() { - throw new UnsupportedOperationException(); - } - public int getPacketBufferSize() { - throw new UnsupportedOperationException(); - } - public javax.security.cert.X509Certificate[] getPeerCertificateChain() { - throw new UnsupportedOperationException(); - } - public Certificate[] getPeerCertificates() { - throw new UnsupportedOperationException(); - } - public String getPeerHost() { - throw new UnsupportedOperationException(); - } - public int getPeerPort() { - throw new UnsupportedOperationException(); - } - public Principal getPeerPrincipal() { - throw new UnsupportedOperationException(); - } - public String getProtocol() { - throw new UnsupportedOperationException(); - } - public SSLSessionContext getSessionContext() { - throw new UnsupportedOperationException(); - } - public Object getValue(String name) { - throw new UnsupportedOperationException(); - } - public String[] getValueNames() { - throw new UnsupportedOperationException(); - } - public void invalidate() { - throw new UnsupportedOperationException(); - } - public boolean isValid() { - throw new UnsupportedOperationException(); - } - public void putValue(String name, Object value) { - throw new UnsupportedOperationException(); - } - public void removeValue(String name) { - throw new UnsupportedOperationException(); - } - } -} diff --git a/apct-tests/perftests/core/src/android/libcore/regression/NumberFormatTrivialFormatLongPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/NumberFormatTrivialFormatLongPerfTest.java new file mode 100644 index 000000000000..5ff2b225d64f --- /dev/null +++ b/apct-tests/perftests/core/src/android/libcore/regression/NumberFormatTrivialFormatLongPerfTest.java @@ -0,0 +1,49 @@ +/* + * 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. + */ + +package android.libcore.regression; + +import android.perftests.utils.BenchmarkState; +import android.perftests.utils.PerfStatusReporter; +import android.test.suitebuilder.annotation.LargeTest; + +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.text.NumberFormat; +import java.util.Locale; + +/** + * Benchmarks creation and cloning various expensive objects. + */ +@RunWith(AndroidJUnit4.class) +@LargeTest +public class NumberFormatTrivialFormatLongPerfTest { + @Rule + public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); + + @Test + public void timeNumberFormatTrivialFormatLong() { + NumberFormat nf = NumberFormat.getInstance(Locale.US); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + nf.format(1024L); + } + } +} diff --git a/api/api.go b/api/api.go index 9cd0132e2c6c..93f1354ce9e4 100644 --- a/api/api.go +++ b/api/api.go @@ -179,7 +179,7 @@ func createFilteredApiVersions(ctx android.LoadHookContext, modules []string) { // Note: order matters: first parameter is the full api-versions.xml // after that the stubs files in any order // stubs files are all modules that export API surfaces EXCEPT ART - props.Srcs = append([]string{":framework-doc-stubs{.api_versions.xml}"}, createSrcs(modules, ".stubs{.jar}")...) + props.Srcs = append([]string{":api_versions_public{.api_versions.xml}"}, createSrcs(modules, ".stubs{.jar}")...) props.Dists = []android.Dist{{Targets: []string{"sdk"}}} ctx.CreateModule(genrule.GenRuleFactory, &props) } diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp index 52fd7be0d768..65826234d30c 100644 --- a/cmds/bootanimation/BootAnimation.cpp +++ b/cmds/bootanimation/BootAnimation.cpp @@ -509,7 +509,8 @@ status_t BootAnimation::readyToRun() { resolution = limitSurfaceSize(resolution.width, resolution.height); // create the native surface sp<SurfaceControl> control = session()->createSurface(String8("BootAnimation"), - resolution.getWidth(), resolution.getHeight(), PIXEL_FORMAT_RGB_565); + resolution.getWidth(), resolution.getHeight(), PIXEL_FORMAT_RGB_565, + ISurfaceComposerClient::eOpaque); SurfaceComposerClient::Transaction t; diff --git a/core/api/current.txt b/core/api/current.txt index e4fc9f3a57d1..18286ebd7a66 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -11473,7 +11473,7 @@ package android.content.pm { field public static final String FEATURE_CAMERA_LEVEL_FULL = "android.hardware.camera.level.full"; field public static final String FEATURE_CANT_SAVE_STATE = "android.software.cant_save_state"; field public static final String FEATURE_COMPANION_DEVICE_SETUP = "android.software.companion_device_setup"; - field public static final String FEATURE_CONNECTION_SERVICE = "android.software.connectionservice"; + field @Deprecated public static final String FEATURE_CONNECTION_SERVICE = "android.software.connectionservice"; field public static final String FEATURE_CONSUMER_IR = "android.hardware.consumerir"; field public static final String FEATURE_CONTROLS = "android.software.controls"; field public static final String FEATURE_DEVICE_ADMIN = "android.software.device_admin"; @@ -11544,12 +11544,18 @@ package android.content.pm { field public static final String FEATURE_SIP = "android.software.sip"; field public static final String FEATURE_SIP_VOIP = "android.software.sip.voip"; field public static final String FEATURE_STRONGBOX_KEYSTORE = "android.hardware.strongbox_keystore"; + field public static final String FEATURE_TELECOM = "android.software.telecom"; field public static final String FEATURE_TELEPHONY = "android.hardware.telephony"; + field public static final String FEATURE_TELEPHONY_CALLING = "android.hardware.telephony.calling"; field public static final String FEATURE_TELEPHONY_CDMA = "android.hardware.telephony.cdma"; + field public static final String FEATURE_TELEPHONY_DATA = "android.hardware.telephony.data"; field public static final String FEATURE_TELEPHONY_EUICC = "android.hardware.telephony.euicc"; field public static final String FEATURE_TELEPHONY_GSM = "android.hardware.telephony.gsm"; field public static final String FEATURE_TELEPHONY_IMS = "android.hardware.telephony.ims"; field public static final String FEATURE_TELEPHONY_MBMS = "android.hardware.telephony.mbms"; + field public static final String FEATURE_TELEPHONY_MESSAGING = "android.hardware.telephony.messaging"; + field public static final String FEATURE_TELEPHONY_RADIO_ACCESS = "android.hardware.telephony.radio"; + field public static final String FEATURE_TELEPHONY_SUBSCRIPTION = "android.hardware.telephony.subscription"; field @Deprecated public static final String FEATURE_TELEVISION = "android.hardware.type.television"; field public static final String FEATURE_TOUCHSCREEN = "android.hardware.touchscreen"; field public static final String FEATURE_TOUCHSCREEN_MULTITOUCH = "android.hardware.touchscreen.multitouch"; @@ -21438,6 +21444,7 @@ package android.media { field public static final String KEY_VIDEO_QP_P_MAX = "video-qp-p-max"; field public static final String KEY_VIDEO_QP_P_MIN = "video-qp-p-min"; field public static final String KEY_WIDTH = "width"; + field public static final String LOG_SESSION_ID = "log-session-id"; field public static final String MIMETYPE_AUDIO_AAC = "audio/mp4a-latm"; field public static final String MIMETYPE_AUDIO_AC3 = "audio/ac3"; field public static final String MIMETYPE_AUDIO_AC4 = "audio/ac4"; @@ -41215,8 +41222,11 @@ package android.telephony { field public static final String MMS_CONFIG_UA_PROF_URL = "uaProfUrl"; field public static final String MMS_CONFIG_USER_AGENT = "userAgent"; field public static final int MMS_ERROR_CONFIGURATION_ERROR = 7; // 0x7 + field public static final int MMS_ERROR_DATA_DISABLED = 11; // 0xb field public static final int MMS_ERROR_HTTP_FAILURE = 4; // 0x4 + field public static final int MMS_ERROR_INACTIVE_SUBSCRIPTION = 10; // 0xa field public static final int MMS_ERROR_INVALID_APN = 2; // 0x2 + field public static final int MMS_ERROR_INVALID_SUBSCRIPTION_ID = 9; // 0x9 field public static final int MMS_ERROR_IO_ERROR = 5; // 0x5 field public static final int MMS_ERROR_NO_DATA_NETWORK = 8; // 0x8 field public static final int MMS_ERROR_RETRY = 6; // 0x6 diff --git a/core/java/android/app/time/ExternalTimeSuggestion.java b/core/java/android/app/time/ExternalTimeSuggestion.java index a7c0e5c79607..a7828ab4c9dc 100644 --- a/core/java/android/app/time/ExternalTimeSuggestion.java +++ b/core/java/android/app/time/ExternalTimeSuggestion.java @@ -19,15 +19,14 @@ package android.app.time; import android.annotation.CurrentTimeMillisLong; import android.annotation.ElapsedRealtimeLong; import android.annotation.NonNull; -import android.annotation.Nullable; import android.annotation.SystemApi; +import android.app.timedetector.TimeSuggestionHelper; import android.os.Parcel; import android.os.Parcelable; +import android.os.ShellCommand; import android.os.TimestampedValue; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; +import java.io.PrintWriter; import java.util.List; import java.util.Objects; @@ -75,7 +74,9 @@ public final class ExternalTimeSuggestion implements Parcelable { public static final @NonNull Creator<ExternalTimeSuggestion> CREATOR = new Creator<ExternalTimeSuggestion>() { public ExternalTimeSuggestion createFromParcel(Parcel in) { - return ExternalTimeSuggestion.createFromParcel(in); + TimeSuggestionHelper helper = TimeSuggestionHelper.handleCreateFromParcel( + ExternalTimeSuggestion.class, in); + return new ExternalTimeSuggestion(helper); } public ExternalTimeSuggestion[] newArray(int size) { @@ -83,10 +84,7 @@ public final class ExternalTimeSuggestion implements Parcelable { } }; - @NonNull - private final TimestampedValue<Long> mUnixEpochTime; - @Nullable - private ArrayList<String> mDebugInfo; + @NonNull private final TimeSuggestionHelper mTimeSuggestionHelper; /** * Creates a time suggestion cross-referenced to the elapsed realtime clock. See {@link @@ -98,17 +96,12 @@ public final class ExternalTimeSuggestion implements Parcelable { */ public ExternalTimeSuggestion(@ElapsedRealtimeLong long elapsedRealtimeMillis, @CurrentTimeMillisLong long suggestionMillis) { - mUnixEpochTime = new TimestampedValue(elapsedRealtimeMillis, suggestionMillis); + mTimeSuggestionHelper = new TimeSuggestionHelper(ExternalTimeSuggestion.class, + new TimestampedValue<>(elapsedRealtimeMillis, suggestionMillis)); } - private static ExternalTimeSuggestion createFromParcel(Parcel in) { - TimestampedValue<Long> utcTime = in.readParcelable(null /* classLoader */); - ExternalTimeSuggestion suggestion = - new ExternalTimeSuggestion(utcTime.getReferenceTimeMillis(), utcTime.getValue()); - @SuppressWarnings("unchecked") - ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(null /* classLoader */); - suggestion.mDebugInfo = debugInfo; - return suggestion; + private ExternalTimeSuggestion(@NonNull TimeSuggestionHelper helper) { + mTimeSuggestionHelper = Objects.requireNonNull(helper); } @Override @@ -118,8 +111,7 @@ public final class ExternalTimeSuggestion implements Parcelable { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeParcelable(mUnixEpochTime, 0); - dest.writeList(mDebugInfo); + mTimeSuggestionHelper.handleWriteToParcel(dest, flags); } /** @@ -127,7 +119,7 @@ public final class ExternalTimeSuggestion implements Parcelable { */ @NonNull public TimestampedValue<Long> getUnixEpochTime() { - return mUnixEpochTime; + return mTimeSuggestionHelper.getUnixEpochTime(); } /** @@ -135,9 +127,7 @@ public final class ExternalTimeSuggestion implements Parcelable { */ @NonNull public List<String> getDebugInfo() { - return mDebugInfo == null - ? Collections.emptyList() - : Collections.unmodifiableList(mDebugInfo); + return mTimeSuggestionHelper.getDebugInfo(); } /** @@ -146,10 +136,7 @@ public final class ExternalTimeSuggestion implements Parcelable { * #equals(Object)} and {@link #hashCode()}. */ public void addDebugInfo(@NonNull String... debugInfos) { - if (mDebugInfo == null) { - mDebugInfo = new ArrayList<>(); - } - mDebugInfo.addAll(Arrays.asList(debugInfos)); + mTimeSuggestionHelper.addDebugInfo(debugInfos); } @Override @@ -161,18 +148,29 @@ public final class ExternalTimeSuggestion implements Parcelable { return false; } ExternalTimeSuggestion that = (ExternalTimeSuggestion) o; - return Objects.equals(mUnixEpochTime, that.mUnixEpochTime); + return mTimeSuggestionHelper.handleEquals(that.mTimeSuggestionHelper); } @Override public int hashCode() { - return Objects.hash(mUnixEpochTime); + return mTimeSuggestionHelper.hashCode(); } @Override public String toString() { - return "ExternalTimeSuggestion{" + "mUnixEpochTime=" + mUnixEpochTime - + ", mDebugInfo=" + mDebugInfo - + '}'; + return mTimeSuggestionHelper.handleToString(); + } + + /** @hide */ + public static ExternalTimeSuggestion parseCommandLineArg(@NonNull ShellCommand cmd) + throws IllegalArgumentException { + return new ExternalTimeSuggestion( + TimeSuggestionHelper.handleParseCommandLineArg(ExternalTimeSuggestion.class, cmd)); + } + + /** @hide */ + public static void printCommandLineOpts(PrintWriter pw) { + TimeSuggestionHelper.handlePrintCommandLineOpts( + pw, "External", ExternalTimeSuggestion.class); } } diff --git a/core/java/android/app/timedetector/GnssTimeSuggestion.java b/core/java/android/app/timedetector/GnssTimeSuggestion.java index 34f4565fb410..3531b19d0f65 100644 --- a/core/java/android/app/timedetector/GnssTimeSuggestion.java +++ b/core/java/android/app/timedetector/GnssTimeSuggestion.java @@ -17,30 +17,19 @@ package android.app.timedetector; import android.annotation.NonNull; -import android.annotation.Nullable; import android.os.Parcel; import android.os.Parcelable; +import android.os.ShellCommand; import android.os.TimestampedValue; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; +import java.io.PrintWriter; import java.util.List; import java.util.Objects; /** * A time signal from a GNSS source. * - * <p>{@code unixEpochTime} is the suggested time. The {@code unixEpochTime.value} is the number of - * milliseconds elapsed since 1/1/1970 00:00:00 UTC according to the Unix time system. The {@code - * unixEpochTime.referenceTimeMillis} is the value of the elapsed realtime clock when the {@code - * unixEpochTime.value} was established. Note that the elapsed realtime clock is considered accurate - * but it is volatile, so time suggestions cannot be persisted across device resets. - * - * <p>{@code debugInfo} contains debugging metadata associated with the suggestion. This is used to - * record why the suggestion exists and how it was entered. This information exists only to aid in - * debugging and therefore is used by {@link #toString()}, but it is not for use in detection - * logic and is not considered in {@link #hashCode()} or {@link #equals(Object)}. + * <p>See {@link TimeSuggestionHelper} for property information. * * @hide */ @@ -49,7 +38,9 @@ public final class GnssTimeSuggestion implements Parcelable { public static final @NonNull Creator<GnssTimeSuggestion> CREATOR = new Creator<GnssTimeSuggestion>() { public GnssTimeSuggestion createFromParcel(Parcel in) { - return GnssTimeSuggestion.createFromParcel(in); + TimeSuggestionHelper helper = TimeSuggestionHelper.handleCreateFromParcel( + GnssTimeSuggestion.class, in); + return new GnssTimeSuggestion(helper); } public GnssTimeSuggestion[] newArray(int size) { @@ -57,21 +48,14 @@ public final class GnssTimeSuggestion implements Parcelable { } }; - @NonNull private final TimestampedValue<Long> mUnixEpochTime; - @Nullable private ArrayList<String> mDebugInfo; + @NonNull private final TimeSuggestionHelper mTimeSuggestionHelper; public GnssTimeSuggestion(@NonNull TimestampedValue<Long> unixEpochTime) { - mUnixEpochTime = Objects.requireNonNull(unixEpochTime); - Objects.requireNonNull(unixEpochTime.getValue()); + mTimeSuggestionHelper = new TimeSuggestionHelper(GnssTimeSuggestion.class, unixEpochTime); } - private static GnssTimeSuggestion createFromParcel(Parcel in) { - TimestampedValue<Long> unixEpochTime = in.readParcelable(null /* classLoader */); - GnssTimeSuggestion suggestion = new GnssTimeSuggestion(unixEpochTime); - @SuppressWarnings("unchecked") - ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(null /* classLoader */); - suggestion.mDebugInfo = debugInfo; - return suggestion; + private GnssTimeSuggestion(@NonNull TimeSuggestionHelper helper) { + mTimeSuggestionHelper = Objects.requireNonNull(helper); } @Override @@ -81,19 +65,17 @@ public final class GnssTimeSuggestion implements Parcelable { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeParcelable(mUnixEpochTime, 0); - dest.writeList(mDebugInfo); + mTimeSuggestionHelper.handleWriteToParcel(dest, flags); } @NonNull public TimestampedValue<Long> getUnixEpochTime() { - return mUnixEpochTime; + return mTimeSuggestionHelper.getUnixEpochTime(); } @NonNull public List<String> getDebugInfo() { - return mDebugInfo == null - ? Collections.emptyList() : Collections.unmodifiableList(mDebugInfo); + return mTimeSuggestionHelper.getDebugInfo(); } /** @@ -102,10 +84,7 @@ public final class GnssTimeSuggestion implements Parcelable { * {@link #equals(Object)} and {@link #hashCode()}. */ public void addDebugInfo(String... debugInfos) { - if (mDebugInfo == null) { - mDebugInfo = new ArrayList<>(); - } - mDebugInfo.addAll(Arrays.asList(debugInfos)); + mTimeSuggestionHelper.addDebugInfo(debugInfos); } @Override @@ -117,19 +96,29 @@ public final class GnssTimeSuggestion implements Parcelable { return false; } GnssTimeSuggestion that = (GnssTimeSuggestion) o; - return Objects.equals(mUnixEpochTime, that.mUnixEpochTime); + return mTimeSuggestionHelper.handleEquals(that.mTimeSuggestionHelper); } @Override public int hashCode() { - return Objects.hash(mUnixEpochTime); + return mTimeSuggestionHelper.hashCode(); } @Override public String toString() { - return "GnssTimeSuggestion{" - + "mUnixEpochTime=" + mUnixEpochTime - + ", mDebugInfo=" + mDebugInfo - + '}'; + return mTimeSuggestionHelper.handleToString(); + } + + /** Parses command line args to create a {@link GnssTimeSuggestion}. */ + public static GnssTimeSuggestion parseCommandLineArg(@NonNull ShellCommand cmd) + throws IllegalArgumentException { + TimeSuggestionHelper suggestionHelper = + TimeSuggestionHelper.handleParseCommandLineArg(GnssTimeSuggestion.class, cmd); + return new GnssTimeSuggestion(suggestionHelper); + } + + /** Prints the command line args needed to create a {@link GnssTimeSuggestion}. */ + public static void printCommandLineOpts(PrintWriter pw) { + TimeSuggestionHelper.handlePrintCommandLineOpts(pw, "GNSS", GnssTimeSuggestion.class); } } diff --git a/core/java/android/app/timedetector/ManualTimeSuggestion.java b/core/java/android/app/timedetector/ManualTimeSuggestion.java index 76db33b1c32b..b447799eb84c 100644 --- a/core/java/android/app/timedetector/ManualTimeSuggestion.java +++ b/core/java/android/app/timedetector/ManualTimeSuggestion.java @@ -20,27 +20,17 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Parcel; import android.os.Parcelable; +import android.os.ShellCommand; import android.os.TimestampedValue; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; +import java.io.PrintWriter; import java.util.List; import java.util.Objects; /** * A time signal from a manual (user provided) source. * - * <p>{@code unixEpochTime} is the suggested time. The {@code unixEpochTime.value} is the number of - * milliseconds elapsed since 1/1/1970 00:00:00 UTC. The {@code unixEpochTime.referenceTimeMillis} - * is the value of the elapsed realtime clock when the {@code unixEpochTime.value} was established. - * Note that the elapsed realtime clock is considered accurate but it is volatile, so time - * suggestions cannot be persisted across device resets. - * - * <p>{@code debugInfo} contains debugging metadata associated with the suggestion. This is used to - * record why the suggestion exists and how it was entered. This information exists only to aid in - * debugging and therefore is used by {@link #toString()}, but it is not for use in detection - * logic and is not considered in {@link #hashCode()} or {@link #equals(Object)}. + * <p>See {@link TimeSuggestionHelper} for property information. * * @hide */ @@ -49,7 +39,9 @@ public final class ManualTimeSuggestion implements Parcelable { public static final @NonNull Creator<ManualTimeSuggestion> CREATOR = new Creator<ManualTimeSuggestion>() { public ManualTimeSuggestion createFromParcel(Parcel in) { - return ManualTimeSuggestion.createFromParcel(in); + TimeSuggestionHelper helper = TimeSuggestionHelper.handleCreateFromParcel( + ManualTimeSuggestion.class, in); + return new ManualTimeSuggestion(helper); } public ManualTimeSuggestion[] newArray(int size) { @@ -57,21 +49,14 @@ public final class ManualTimeSuggestion implements Parcelable { } }; - @NonNull private final TimestampedValue<Long> mUnixEpochTime; - @Nullable private ArrayList<String> mDebugInfo; + @NonNull private final TimeSuggestionHelper mTimeSuggestionHelper; public ManualTimeSuggestion(@NonNull TimestampedValue<Long> unixEpochTime) { - mUnixEpochTime = Objects.requireNonNull(unixEpochTime); - Objects.requireNonNull(unixEpochTime.getValue()); + mTimeSuggestionHelper = new TimeSuggestionHelper(ManualTimeSuggestion.class, unixEpochTime); } - private static ManualTimeSuggestion createFromParcel(Parcel in) { - TimestampedValue<Long> unixEpochTime = in.readParcelable(null /* classLoader */); - ManualTimeSuggestion suggestion = new ManualTimeSuggestion(unixEpochTime); - @SuppressWarnings("unchecked") - ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(null /* classLoader */); - suggestion.mDebugInfo = debugInfo; - return suggestion; + private ManualTimeSuggestion(@NonNull TimeSuggestionHelper helper) { + mTimeSuggestionHelper = Objects.requireNonNull(helper); } @Override @@ -81,19 +66,17 @@ public final class ManualTimeSuggestion implements Parcelable { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeParcelable(mUnixEpochTime, 0); - dest.writeList(mDebugInfo); + mTimeSuggestionHelper.handleWriteToParcel(dest, flags); } @NonNull public TimestampedValue<Long> getUnixEpochTime() { - return mUnixEpochTime; + return mTimeSuggestionHelper.getUnixEpochTime(); } @NonNull public List<String> getDebugInfo() { - return mDebugInfo == null - ? Collections.emptyList() : Collections.unmodifiableList(mDebugInfo); + return mTimeSuggestionHelper.getDebugInfo(); } /** @@ -102,10 +85,7 @@ public final class ManualTimeSuggestion implements Parcelable { * {@link #equals(Object)} and {@link #hashCode()}. */ public void addDebugInfo(String... debugInfos) { - if (mDebugInfo == null) { - mDebugInfo = new ArrayList<>(); - } - mDebugInfo.addAll(Arrays.asList(debugInfos)); + mTimeSuggestionHelper.addDebugInfo(debugInfos); } @Override @@ -117,19 +97,28 @@ public final class ManualTimeSuggestion implements Parcelable { return false; } ManualTimeSuggestion that = (ManualTimeSuggestion) o; - return Objects.equals(mUnixEpochTime, that.mUnixEpochTime); + return mTimeSuggestionHelper.handleEquals(that.mTimeSuggestionHelper); } @Override public int hashCode() { - return Objects.hash(mUnixEpochTime); + return mTimeSuggestionHelper.hashCode(); } @Override public String toString() { - return "ManualTimeSuggestion{" - + "mUnixEpochTime=" + mUnixEpochTime - + ", mDebugInfo=" + mDebugInfo - + '}'; + return mTimeSuggestionHelper.handleToString(); + } + + /** @hide */ + public static ManualTimeSuggestion parseCommandLineArg(@NonNull ShellCommand cmd) + throws IllegalArgumentException { + return new ManualTimeSuggestion( + TimeSuggestionHelper.handleParseCommandLineArg(ManualTimeSuggestion.class, cmd)); + } + + /** @hide */ + public static void printCommandLineOpts(PrintWriter pw) { + TimeSuggestionHelper.handlePrintCommandLineOpts(pw, "Manual", ManualTimeSuggestion.class); } } diff --git a/core/java/android/app/timedetector/NetworkTimeSuggestion.java b/core/java/android/app/timedetector/NetworkTimeSuggestion.java index e22f1d6ea8be..e93c75cb0a0c 100644 --- a/core/java/android/app/timedetector/NetworkTimeSuggestion.java +++ b/core/java/android/app/timedetector/NetworkTimeSuggestion.java @@ -17,31 +17,19 @@ package android.app.timedetector; import android.annotation.NonNull; -import android.annotation.Nullable; import android.os.Parcel; import android.os.Parcelable; +import android.os.ShellCommand; import android.os.TimestampedValue; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; +import java.io.PrintWriter; import java.util.List; import java.util.Objects; /** * A time signal from a network time source like NTP. * - * <p>{@code unixEpochTime} contains the suggested time. The {@code unixEpochTime.value} is the - * number of milliseconds elapsed since 1/1/1970 00:00:00 UTC according to the Unix time system. - * The {@code unixEpochTime.referenceTimeMillis} is the value of the elapsed realtime clock when - * the {@code unixEpochTime.value} was established. Note that the elapsed realtime clock is - * considered accurate but it is volatile, so time suggestions cannot be persisted across device - * resets. - * - * <p>{@code debugInfo} contains debugging metadata associated with the suggestion. This is used to - * record why the suggestion exists and how it was determined. This information exists only to aid - * in debugging and therefore is used by {@link #toString()}, but it is not for use in detection - * logic and is not considered in {@link #hashCode()} or {@link #equals(Object)}. + * <p>See {@link TimeSuggestionHelper} for property information. * * @hide */ @@ -50,7 +38,9 @@ public final class NetworkTimeSuggestion implements Parcelable { public static final @NonNull Creator<NetworkTimeSuggestion> CREATOR = new Creator<NetworkTimeSuggestion>() { public NetworkTimeSuggestion createFromParcel(Parcel in) { - return NetworkTimeSuggestion.createFromParcel(in); + TimeSuggestionHelper helper = TimeSuggestionHelper.handleCreateFromParcel( + NetworkTimeSuggestion.class, in); + return new NetworkTimeSuggestion(helper); } public NetworkTimeSuggestion[] newArray(int size) { @@ -58,21 +48,15 @@ public final class NetworkTimeSuggestion implements Parcelable { } }; - @NonNull private final TimestampedValue<Long> mUnixEpochTime; - @Nullable private ArrayList<String> mDebugInfo; + @NonNull private final TimeSuggestionHelper mTimeSuggestionHelper; public NetworkTimeSuggestion(@NonNull TimestampedValue<Long> unixEpochTime) { - mUnixEpochTime = Objects.requireNonNull(unixEpochTime); - Objects.requireNonNull(unixEpochTime.getValue()); + mTimeSuggestionHelper = new TimeSuggestionHelper( + NetworkTimeSuggestion.class, unixEpochTime); } - private static NetworkTimeSuggestion createFromParcel(Parcel in) { - TimestampedValue<Long> unixEpochTime = in.readParcelable(null /* classLoader */); - NetworkTimeSuggestion suggestion = new NetworkTimeSuggestion(unixEpochTime); - @SuppressWarnings("unchecked") - ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(null /* classLoader */); - suggestion.mDebugInfo = debugInfo; - return suggestion; + private NetworkTimeSuggestion(@NonNull TimeSuggestionHelper helper) { + mTimeSuggestionHelper = Objects.requireNonNull(helper); } @Override @@ -82,35 +66,30 @@ public final class NetworkTimeSuggestion implements Parcelable { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeParcelable(mUnixEpochTime, 0); - dest.writeList(mDebugInfo); + mTimeSuggestionHelper.handleWriteToParcel(dest, flags); } @NonNull public TimestampedValue<Long> getUnixEpochTime() { - return mUnixEpochTime; + return mTimeSuggestionHelper.getUnixEpochTime(); } @NonNull public List<String> getDebugInfo() { - return mDebugInfo == null - ? Collections.emptyList() : Collections.unmodifiableList(mDebugInfo); + return mTimeSuggestionHelper.getDebugInfo(); } /** * Associates information with the instance that can be useful for debugging / logging. The - * information is present in {@link #toString()} but is not considered for - * {@link #equals(Object)} and {@link #hashCode()}. + * information is present in {@link #toString()} but is not considered for {@link + * #equals(Object)} and {@link #hashCode()}. */ public void addDebugInfo(String... debugInfos) { - if (mDebugInfo == null) { - mDebugInfo = new ArrayList<>(); - } - mDebugInfo.addAll(Arrays.asList(debugInfos)); + mTimeSuggestionHelper.addDebugInfo(debugInfos); } @Override - public boolean equals(@Nullable Object o) { + public boolean equals(Object o) { if (this == o) { return true; } @@ -118,19 +97,28 @@ public final class NetworkTimeSuggestion implements Parcelable { return false; } NetworkTimeSuggestion that = (NetworkTimeSuggestion) o; - return Objects.equals(mUnixEpochTime, that.mUnixEpochTime); + return mTimeSuggestionHelper.handleEquals(that.mTimeSuggestionHelper); } @Override public int hashCode() { - return Objects.hash(mUnixEpochTime); + return mTimeSuggestionHelper.hashCode(); } @Override public String toString() { - return "NetworkTimeSuggestion{" - + "mUnixEpochTime=" + mUnixEpochTime - + ", mDebugInfo=" + mDebugInfo - + '}'; + return mTimeSuggestionHelper.handleToString(); + } + + /** @hide */ + public static NetworkTimeSuggestion parseCommandLineArg(@NonNull ShellCommand cmd) + throws IllegalArgumentException { + return new NetworkTimeSuggestion( + TimeSuggestionHelper.handleParseCommandLineArg(NetworkTimeSuggestion.class, cmd)); + } + + /** @hide */ + public static void printCommandLineOpts(PrintWriter pw) { + TimeSuggestionHelper.handlePrintCommandLineOpts(pw, "Network", NetworkTimeSuggestion.class); } } diff --git a/core/java/android/app/timedetector/TelephonyTimeSuggestion.java b/core/java/android/app/timedetector/TelephonyTimeSuggestion.java index 4ff75174ab57..6f204d661004 100644 --- a/core/java/android/app/timedetector/TelephonyTimeSuggestion.java +++ b/core/java/android/app/timedetector/TelephonyTimeSuggestion.java @@ -20,8 +20,10 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Parcel; import android.os.Parcelable; +import android.os.ShellCommand; import android.os.TimestampedValue; +import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -88,6 +90,61 @@ public final class TelephonyTimeSuggestion implements Parcelable { return suggestion; } + /** @hide */ + public static TelephonyTimeSuggestion parseCommandLineArg(@NonNull ShellCommand cmd) + throws IllegalArgumentException { + Integer slotIndex = null; + Long referenceTimeMillis = null; + Long unixEpochTimeMillis = null; + String opt; + while ((opt = cmd.getNextArg()) != null) { + switch (opt) { + case "--slot_index": { + slotIndex = Integer.parseInt(cmd.getNextArgRequired()); + break; + } + case "--reference_time": { + referenceTimeMillis = Long.parseLong(cmd.getNextArgRequired()); + break; + } + case "--unix_epoch_time": { + unixEpochTimeMillis = Long.parseLong(cmd.getNextArgRequired()); + break; + } + default: { + throw new IllegalArgumentException("Unknown option: " + opt); + } + } + } + + if (slotIndex == null) { + throw new IllegalArgumentException("No slotIndex specified."); + } + if (referenceTimeMillis == null) { + throw new IllegalArgumentException("No referenceTimeMillis specified."); + } + if (unixEpochTimeMillis == null) { + throw new IllegalArgumentException("No unixEpochTimeMillis specified."); + } + + TimestampedValue<Long> timeSignal = + new TimestampedValue<>(referenceTimeMillis, unixEpochTimeMillis); + Builder builder = new Builder(slotIndex) + .setUnixEpochTime(timeSignal) + .addDebugInfo("Command line injection"); + return builder.build(); + } + + /** @hide */ + public static void printCommandLineOpts(PrintWriter pw) { + pw.println("Telephony suggestion options:"); + pw.println(" --slot_index <number>"); + pw.println(" --reference_time <elapsed realtime millis>"); + pw.println(" --unix_epoch_time <Unix epoch time millis>"); + pw.println(); + pw.println("See " + TelephonyTimeSuggestion.class.getName() + " for more information"); + } + @Override public int describeContents() { return 0; diff --git a/core/java/android/app/timedetector/TimeDetector.java b/core/java/android/app/timedetector/TimeDetector.java index a3562301cde7..f0d777611620 100644 --- a/core/java/android/app/timedetector/TimeDetector.java +++ b/core/java/android/app/timedetector/TimeDetector.java @@ -44,6 +44,36 @@ public interface TimeDetector { String SHELL_COMMAND_IS_AUTO_DETECTION_ENABLED = "is_auto_detection_enabled"; /** + * A shell command that injects a manual time suggestion. + * @hide + */ + String SHELL_COMMAND_SUGGEST_MANUAL_TIME = "suggest_manual_time"; + + /** + * A shell command that injects a telephony time suggestion. + * @hide + */ + String SHELL_COMMAND_SUGGEST_TELEPHONY_TIME = "suggest_telephony_time"; + + /** + * A shell command that injects a network time suggestion. + * @hide + */ + String SHELL_COMMAND_SUGGEST_NETWORK_TIME = "suggest_network_time"; + + /** + * A shell command that injects a GNSS time suggestion. + * @hide + */ + String SHELL_COMMAND_SUGGEST_GNSS_TIME = "suggest_gnss_time"; + + /** + * A shell command that injects a external time suggestion. + * @hide + */ + String SHELL_COMMAND_SUGGEST_EXTERNAL_TIME = "suggest_external_time"; + + /** * A shared utility method to create a {@link ManualTimeSuggestion}. * * @hide diff --git a/core/java/android/app/timedetector/TimeSuggestionHelper.java b/core/java/android/app/timedetector/TimeSuggestionHelper.java new file mode 100644 index 000000000000..9b99be61b3c8 --- /dev/null +++ b/core/java/android/app/timedetector/TimeSuggestionHelper.java @@ -0,0 +1,209 @@ +/* + * 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. + */ + +package android.app.timedetector; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.Parcel; +import android.os.ShellCommand; +import android.os.TimestampedValue; + +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +/** + * A delegate class to support time suggestion classes that could diverge in the future. This class + * exists purely for code re-use and provides support methods. It avoids class inheritance + * deliberately to allow each suggestion to evolve in different directions later without affecting + * SDK APIs. + * + * <p>{@code unixEpochTime} is the suggested time. The {@code unixEpochTime.value} is the number of + * milliseconds elapsed since 1/1/1970 00:00:00 UTC according to the Unix time system. The {@code + * unixEpochTime.referenceTimeMillis} is the value of the elapsed realtime clock when the {@code + * unixEpochTime.value} was established. Note that the elapsed realtime clock is considered accurate + * but it is volatile, so time suggestions cannot be persisted across device resets. + * + * <p>{@code debugInfo} contains debugging metadata associated with the suggestion. This is used to + * record why the suggestion exists and how it was entered. This information exists only to aid in + * debugging and therefore is used by {@link #toString()}, but it is not for use in detection + * logic and is not considered in {@link #hashCode()} or {@link #equals(Object)}. + * + * @hide + */ +public final class TimeSuggestionHelper { + + @NonNull private final Class<?> mHelpedClass; + @NonNull private final TimestampedValue<Long> mUnixEpochTime; + @Nullable private ArrayList<String> mDebugInfo; + + /** Creates a helper for the specified class, containing the supplied properties. */ + public TimeSuggestionHelper(@NonNull Class<?> helpedClass, + @NonNull TimestampedValue<Long> unixEpochTime) { + mHelpedClass = Objects.requireNonNull(helpedClass); + mUnixEpochTime = Objects.requireNonNull(unixEpochTime); + Objects.requireNonNull(unixEpochTime.getValue()); + } + + /** See {@link TimeSuggestionHelper} for property details. */ + @NonNull + public TimestampedValue<Long> getUnixEpochTime() { + return mUnixEpochTime; + } + + /** See {@link TimeSuggestionHelper} for information about {@code debugInfo}. */ + @NonNull + public List<String> getDebugInfo() { + return mDebugInfo == null + ? Collections.emptyList() : Collections.unmodifiableList(mDebugInfo); + } + + /** + * Associates information with the instance that can be useful for debugging / logging. + * + * <p>See {@link TimeSuggestionHelper} for more information about {@code debugInfo}. + */ + public void addDebugInfo(@NonNull String debugInfo) { + if (mDebugInfo == null) { + mDebugInfo = new ArrayList<>(); + } + mDebugInfo.add(debugInfo); + } + + /** + * Associates information with the instance that can be useful for debugging / logging. The + * information is present in {@link #toString()} but is not considered for + * {@link #equals(Object)} and {@link #hashCode()}. + */ + public void addDebugInfo(String... debugInfos) { + addDebugInfo(Arrays.asList(debugInfos)); + } + + /** + * Associates information with the instance that can be useful for debugging / logging. + * + * <p>See {@link TimeSuggestionHelper} for more information about {@code debugInfo}. + */ + public void addDebugInfo(@NonNull List<String> debugInfo) { + if (mDebugInfo == null) { + mDebugInfo = new ArrayList<>(debugInfo.size()); + } + mDebugInfo.addAll(debugInfo); + } + + /** + * Implemented in case users call this insteam of {@link #handleEquals(TimeSuggestionHelper)}. + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + TimeSuggestionHelper that = (TimeSuggestionHelper) o; + return handleEquals(that); + } + + /** Used to implement {@link Object#equals(Object)}. */ + public boolean handleEquals(TimeSuggestionHelper o) { + return Objects.equals(mHelpedClass, o.mHelpedClass) + && Objects.equals(mUnixEpochTime, o.mUnixEpochTime); + } + + @Override + public int hashCode() { + return Objects.hash(mUnixEpochTime); + } + + /** Used to implement {@link Object#toString()}. */ + public String handleToString() { + return mHelpedClass.getSimpleName() + "{" + + "mUnixEpochTime=" + mUnixEpochTime + + ", mDebugInfo=" + mDebugInfo + + '}'; + } + + /** Constructs a helper with suggestion state from a Parcel. */ + public static TimeSuggestionHelper handleCreateFromParcel(@NonNull Class<?> helpedClass, + @NonNull Parcel in) { + @SuppressWarnings("unchecked") + TimestampedValue<Long> unixEpochTime = in.readParcelable( + null /* classLoader */, TimestampedValue.class); + TimeSuggestionHelper suggestionHelper = + new TimeSuggestionHelper(helpedClass, unixEpochTime); + suggestionHelper.mDebugInfo = in.readArrayList(null /* classLoader */, String.class); + return suggestionHelper; + } + + /** Writes the helper suggestion state to a Parcel. */ + public void handleWriteToParcel(@NonNull Parcel dest, int flags) { + dest.writeParcelable(mUnixEpochTime, 0); + dest.writeList(mDebugInfo); + } + + /** Parses command line args to create a {@link TimeSuggestionHelper}. */ + public static TimeSuggestionHelper handleParseCommandLineArg( + @NonNull Class<?> helpedClass, @NonNull ShellCommand cmd) + throws IllegalArgumentException { + Long referenceTimeMillis = null; + Long unixEpochTimeMillis = null; + String opt; + while ((opt = cmd.getNextArg()) != null) { + switch (opt) { + case "--reference_time": { + referenceTimeMillis = Long.parseLong(cmd.getNextArgRequired()); + break; + } + case "--unix_epoch_time": { + unixEpochTimeMillis = Long.parseLong(cmd.getNextArgRequired()); + break; + } + default: { + throw new IllegalArgumentException("Unknown option: " + opt); + } + } + } + + if (referenceTimeMillis == null) { + throw new IllegalArgumentException("No referenceTimeMillis specified."); + } + if (unixEpochTimeMillis == null) { + throw new IllegalArgumentException("No unixEpochTimeMillis specified."); + } + + TimestampedValue<Long> timeSignal = + new TimestampedValue<>(referenceTimeMillis, unixEpochTimeMillis); + TimeSuggestionHelper suggestionHelper = new TimeSuggestionHelper(helpedClass, timeSignal); + suggestionHelper.addDebugInfo("Command line injection"); + return suggestionHelper; + } + + /** Prints the command line args needed to create a {@link TimeSuggestionHelper}. */ + public static void handlePrintCommandLineOpts( + @NonNull PrintWriter pw, @NonNull String typeName, @NonNull Class<?> clazz) { + pw.printf("%s suggestion options:\n", typeName); + pw.println(" --reference_time <elapsed realtime millis>"); + pw.println(" --unix_epoch_time <Unix epoch time millis>"); + pw.println(); + pw.println("See " + clazz.getName() + " for more information"); + } +} diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 511901037a30..ce2121413919 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -2929,6 +2929,8 @@ public abstract class PackageManager { /** * Feature for {@link #getSystemAvailableFeatures} and * {@link #hasSystemFeature}: The device has a CDMA telephony stack. + * + * <p>This feature should only be defined if {@link #FEATURE_TELEPHONY} has been defined. */ @SdkConstant(SdkConstantType.FEATURE) public static final String FEATURE_TELEPHONY_CDMA = "android.hardware.telephony.cdma"; @@ -2936,6 +2938,8 @@ public abstract class PackageManager { /** * Feature for {@link #getSystemAvailableFeatures} and * {@link #hasSystemFeature}: The device has a GSM telephony stack. + * + * <p>This feature should only be defined if {@link #FEATURE_TELEPHONY} has been defined. */ @SdkConstant(SdkConstantType.FEATURE) public static final String FEATURE_TELEPHONY_GSM = "android.hardware.telephony.gsm"; @@ -2947,6 +2951,9 @@ public abstract class PackageManager { * <p>Devices declaring this feature must have an implementation of the * {@link android.telephony.TelephonyManager#getAllowedCarriers} and * {@link android.telephony.TelephonyManager#setAllowedCarriers}. + * + * This feature should only be defined if {@link #FEATURE_TELEPHONY_SUBSCRIPTION} + * has been defined. * @hide */ @SystemApi @@ -2957,6 +2964,9 @@ public abstract class PackageManager { /** * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device * supports embedded subscriptions on eUICCs. + * + * This feature should only be defined if {@link #FEATURE_TELEPHONY_SUBSCRIPTION} + * has been defined. */ @SdkConstant(SdkConstantType.FEATURE) public static final String FEATURE_TELEPHONY_EUICC = "android.hardware.telephony.euicc"; @@ -2964,6 +2974,9 @@ public abstract class PackageManager { /** * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device * supports cell-broadcast reception using the MBMS APIs. + * + * <p>This feature should only be defined if both {@link #FEATURE_TELEPHONY_SUBSCRIPTION} + * and {@link #FEATURE_TELEPHONY_RADIO_ACCESS} have been defined. */ @SdkConstant(SdkConstantType.FEATURE) public static final String FEATURE_TELEPHONY_MBMS = "android.hardware.telephony.mbms"; @@ -2971,6 +2984,8 @@ public abstract class PackageManager { /** * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device * supports attaching to IMS implementations using the ImsService API in telephony. + * + * <p>This feature should only be defined if {@link #FEATURE_TELEPHONY_DATA} has been defined. */ @SdkConstant(SdkConstantType.FEATURE) public static final String FEATURE_TELEPHONY_IMS = "android.hardware.telephony.ims"; @@ -3007,6 +3022,62 @@ public abstract class PackageManager { "android.hardware.telephony.ims.singlereg"; /** + * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: + * The device supports Telecom Service APIs. + */ + @SdkConstant(SdkConstantType.FEATURE) + public static final String FEATURE_TELECOM = "android.software.telecom"; + + /** + * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: + * The device supports Telephony APIs for calling service. + * + * <p>This feature should only be defined if {@link #FEATURE_TELEPHONY_RADIO_ACCESS}, + * {@link #FEATURE_TELEPHONY_SUBSCRIPTION}, and {@link #FEATURE_TELECOM} have been defined. + */ + @SdkConstant(SdkConstantType.FEATURE) + public static final String FEATURE_TELEPHONY_CALLING = "android.hardware.telephony.calling"; + + /** + * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: + * The device supports Telephony APIs for data service. + * + * <p>This feature should only be defined if both {@link #FEATURE_TELEPHONY_SUBSCRIPTION} + * and {@link #FEATURE_TELEPHONY_RADIO_ACCESS} have been defined. + */ + @SdkConstant(SdkConstantType.FEATURE) + public static final String FEATURE_TELEPHONY_DATA = "android.hardware.telephony.data"; + + /** + * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: + * The device supports Telephony APIs for SMS and MMS. + * + * <p>This feature should only be defined if both {@link #FEATURE_TELEPHONY_SUBSCRIPTION} + * and {@link #FEATURE_TELEPHONY_RADIO_ACCESS} have been defined. + */ + @SdkConstant(SdkConstantType.FEATURE) + public static final String FEATURE_TELEPHONY_MESSAGING = "android.hardware.telephony.messaging"; + + /** + * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: + * The device supports Telephony APIs for the radio access. + * + * <p>This feature should only be defined if {@link #FEATURE_TELEPHONY} has been defined. + */ + @SdkConstant(SdkConstantType.FEATURE) + public static final String FEATURE_TELEPHONY_RADIO_ACCESS = "android.hardware.telephony.radio"; + + /** + * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: + * The device supports Telephony APIs for the subscription. + * + * <p>This feature should only be defined if {@link #FEATURE_TELEPHONY} has been defined. + */ + @SdkConstant(SdkConstantType.FEATURE) + public static final String FEATURE_TELEPHONY_SUBSCRIPTION = + "android.hardware.telephony.subscription"; + + /** * Feature for {@link #getSystemAvailableFeatures} and * {@link #hasSystemFeature}: The device is capable of communicating with * other devices via ultra wideband. @@ -3047,7 +3118,9 @@ public abstract class PackageManager { /** * Feature for {@link #getSystemAvailableFeatures} and * {@link #hasSystemFeature}: The Connection Service API is enabled on the device. + * @deprecated use {@link #FEATURE_TELECOM} instead. */ + @Deprecated @SdkConstant(SdkConstantType.FEATURE) public static final String FEATURE_CONNECTION_SERVICE = "android.software.connectionservice"; diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml index b3851a5ffbf2..d24a95db3cd9 100644 --- a/core/res/res/values/config_telephony.xml +++ b/core/res/res/values/config_telephony.xml @@ -35,7 +35,7 @@ rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max If this is configured as an empty string, the system default will be applied. --> - <string name="config_tcp_buffers" translatable="false"></string> + <string name="config_tcp_buffers" translatable="false">2097152,6291456,16777216,512000,2097152,8388608</string> <java-symbol type="string" name="config_tcp_buffers" /> <!-- What source to use to estimate link upstream and downstream bandwidth capacities. @@ -109,4 +109,12 @@ <!-- Telephony qualified networks service class name to bind to by default. --> <string name="config_qualified_networks_service_class" translatable="false"></string> <java-symbol type="string" name="config_qualified_networks_service_class" /> + + <!-- Whether enhanced IWLAN handover check is enabled. If enabled, telephony frameworks + will not perform handover if the target transport is out of service, or VoPS not + supported. The network will be torn down on the source transport, and will be + re-established on the target transport when condition is allowed for bringing up a + new network. --> + <bool name="config_enhanced_iwlan_handover_check">true</bool> + <java-symbol type="bool" name="config_enhanced_iwlan_handover_check" /> </resources> diff --git a/core/tests/PackageInstallerSessions/Android.bp b/core/tests/PackageInstallerSessions/Android.bp index c112cbb47b55..6f2366e32574 100644 --- a/core/tests/PackageInstallerSessions/Android.bp +++ b/core/tests/PackageInstallerSessions/Android.bp @@ -50,7 +50,6 @@ android_test { ":PackageManagerTestAppVersion1", ], - platform_apis: true, sdk_version: "core_platform", test_suites: ["device-tests"], } diff --git a/core/tests/bugreports/Android.bp b/core/tests/bugreports/Android.bp index f87797a90c90..2b34ee2646f3 100644 --- a/core/tests/bugreports/Android.bp +++ b/core/tests/bugreports/Android.bp @@ -36,7 +36,6 @@ android_test { ], test_suites: ["general-tests"], sdk_version: "test_current", - platform_apis: true, } filegroup { diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp index 05ec00fe84f0..f971af1466c3 100644 --- a/core/tests/coretests/Android.bp +++ b/core/tests/coretests/Android.bp @@ -72,7 +72,6 @@ android_test { "libpowermanagertest_jni", ], - platform_apis: true, sdk_version: "core_platform", test_suites: ["device-tests"], diff --git a/core/tests/coretests/src/android/app/time/ExternalTimeSuggestionTest.java b/core/tests/coretests/src/android/app/time/ExternalTimeSuggestionTest.java new file mode 100644 index 000000000000..90b33058d4e8 --- /dev/null +++ b/core/tests/coretests/src/android/app/time/ExternalTimeSuggestionTest.java @@ -0,0 +1,63 @@ +/* + * Copyright 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. + */ + +package android.app.time; + +import static android.app.timezonedetector.ShellCommandTestSupport.createShellCommandWithArgsAndOptions; + +import static org.junit.Assert.assertEquals; + +import android.os.ShellCommand; + +import org.junit.Test; + +/** + * Tests for non-SDK methods on {@link ExternalTimeSuggestion}. + * Also see {@link android.app.time.cts.ExternalTimeSuggestionTest} + */ +public class ExternalTimeSuggestionTest { + + @Test(expected = IllegalArgumentException.class) + public void testParseCommandLineArg_noReferenceTime() { + ShellCommand testShellCommand = createShellCommandWithArgsAndOptions( + "--unix_epoch_time 12345"); + ExternalTimeSuggestion.parseCommandLineArg(testShellCommand); + } + + @Test(expected = IllegalArgumentException.class) + public void testParseCommandLineArg_noUnixEpochTime() { + ShellCommand testShellCommand = createShellCommandWithArgsAndOptions( + "--reference_time 54321"); + ExternalTimeSuggestion.parseCommandLineArg(testShellCommand); + } + + @Test + public void testParseCommandLineArg_validSuggestion() { + ShellCommand testShellCommand = createShellCommandWithArgsAndOptions( + "--reference_time 54321 --unix_epoch_time 12345"); + ExternalTimeSuggestion expectedSuggestion = new ExternalTimeSuggestion(54321L, 12345L); + ExternalTimeSuggestion actualSuggestion = + ExternalTimeSuggestion.parseCommandLineArg(testShellCommand); + assertEquals(expectedSuggestion, actualSuggestion); + } + + @Test(expected = IllegalArgumentException.class) + public void testParseCommandLineArg_unknownArgument() { + ShellCommand testShellCommand = createShellCommandWithArgsAndOptions( + "--reference_time 54321 --unix_epoch_time 12345 --bad_arg 0"); + ExternalTimeSuggestion.parseCommandLineArg(testShellCommand); + } +} diff --git a/core/tests/coretests/src/android/app/timedetector/GnssTimeSuggestionTest.java b/core/tests/coretests/src/android/app/timedetector/GnssTimeSuggestionTest.java index e248010319e1..af403a20ae7b 100644 --- a/core/tests/coretests/src/android/app/timedetector/GnssTimeSuggestionTest.java +++ b/core/tests/coretests/src/android/app/timedetector/GnssTimeSuggestionTest.java @@ -18,10 +18,12 @@ package android.app.timedetector; import static android.app.timezonedetector.ParcelableTestSupport.assertRoundTripParcelable; import static android.app.timezonedetector.ParcelableTestSupport.roundTripParcelable; +import static android.app.timezonedetector.ShellCommandTestSupport.createShellCommandWithArgsAndOptions; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; +import android.os.ShellCommand; import android.os.TimestampedValue; import org.junit.Test; @@ -63,4 +65,36 @@ public class GnssTimeSuggestionTest { GnssTimeSuggestion rtSuggestion = roundTripParcelable(suggestion); assertEquals(suggestion.getDebugInfo(), rtSuggestion.getDebugInfo()); } + + @Test(expected = IllegalArgumentException.class) + public void testParseCommandLineArg_noReferenceTime() { + ShellCommand testShellCommand = createShellCommandWithArgsAndOptions( + "--unix_epoch_time 12345"); + GnssTimeSuggestion.parseCommandLineArg(testShellCommand); + } + + @Test(expected = IllegalArgumentException.class) + public void testParseCommandLineArg_noUnixEpochTime() { + ShellCommand testShellCommand = createShellCommandWithArgsAndOptions( + "--reference_time 54321"); + GnssTimeSuggestion.parseCommandLineArg(testShellCommand); + } + + @Test + public void testParseCommandLineArg_validSuggestion() { + ShellCommand testShellCommand = createShellCommandWithArgsAndOptions( + "--reference_time 54321 --unix_epoch_time 12345"); + TimestampedValue<Long> timeSignal = new TimestampedValue<>(54321L, 12345L); + GnssTimeSuggestion expectedSuggestion = new GnssTimeSuggestion(timeSignal); + GnssTimeSuggestion actualSuggestion = + GnssTimeSuggestion.parseCommandLineArg(testShellCommand); + assertEquals(expectedSuggestion, actualSuggestion); + } + + @Test(expected = IllegalArgumentException.class) + public void testParseCommandLineArg_unknownArgument() { + ShellCommand testShellCommand = createShellCommandWithArgsAndOptions( + "--reference_time 54321 --unix_epoch_time 12345 --bad_arg 0"); + GnssTimeSuggestion.parseCommandLineArg(testShellCommand); + } } diff --git a/core/tests/coretests/src/android/app/timedetector/ManualTimeSuggestionTest.java b/core/tests/coretests/src/android/app/timedetector/ManualTimeSuggestionTest.java index 750ffa1c9a54..94218cdea0ed 100644 --- a/core/tests/coretests/src/android/app/timedetector/ManualTimeSuggestionTest.java +++ b/core/tests/coretests/src/android/app/timedetector/ManualTimeSuggestionTest.java @@ -18,10 +18,12 @@ package android.app.timedetector; import static android.app.timezonedetector.ParcelableTestSupport.assertRoundTripParcelable; import static android.app.timezonedetector.ParcelableTestSupport.roundTripParcelable; +import static android.app.timezonedetector.ShellCommandTestSupport.createShellCommandWithArgsAndOptions; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; +import android.os.ShellCommand; import android.os.TimestampedValue; import org.junit.Test; @@ -63,4 +65,36 @@ public class ManualTimeSuggestionTest { ManualTimeSuggestion rtSuggestion = roundTripParcelable(suggestion); assertEquals(suggestion.getDebugInfo(), rtSuggestion.getDebugInfo()); } + + @Test(expected = IllegalArgumentException.class) + public void testParseCommandLineArg_noReferenceTime() { + ShellCommand testShellCommand = createShellCommandWithArgsAndOptions( + "--unix_epoch_time 12345"); + ManualTimeSuggestion.parseCommandLineArg(testShellCommand); + } + + @Test(expected = IllegalArgumentException.class) + public void testParseCommandLineArg_noUnixEpochTime() { + ShellCommand testShellCommand = createShellCommandWithArgsAndOptions( + "--reference_time 54321"); + ManualTimeSuggestion.parseCommandLineArg(testShellCommand); + } + + @Test + public void testParseCommandLineArg_validSuggestion() { + ShellCommand testShellCommand = createShellCommandWithArgsAndOptions( + "--reference_time 54321 --unix_epoch_time 12345"); + TimestampedValue<Long> timeSignal = new TimestampedValue<>(54321L, 12345L); + ManualTimeSuggestion expectedSuggestion = new ManualTimeSuggestion(timeSignal); + ManualTimeSuggestion actualSuggestion = + ManualTimeSuggestion.parseCommandLineArg(testShellCommand); + assertEquals(expectedSuggestion, actualSuggestion); + } + + @Test(expected = IllegalArgumentException.class) + public void testParseCommandLineArg_unknownArgument() { + ShellCommand testShellCommand = createShellCommandWithArgsAndOptions( + "--reference_time 54321 --unix_epoch_time 12345 --bad_arg 0"); + ManualTimeSuggestion.parseCommandLineArg(testShellCommand); + } } diff --git a/core/tests/coretests/src/android/app/timedetector/NetworkTimeSuggestionTest.java b/core/tests/coretests/src/android/app/timedetector/NetworkTimeSuggestionTest.java index b88c36f20bc6..0e09dd3e9aab 100644 --- a/core/tests/coretests/src/android/app/timedetector/NetworkTimeSuggestionTest.java +++ b/core/tests/coretests/src/android/app/timedetector/NetworkTimeSuggestionTest.java @@ -18,10 +18,12 @@ package android.app.timedetector; import static android.app.timezonedetector.ParcelableTestSupport.assertRoundTripParcelable; import static android.app.timezonedetector.ParcelableTestSupport.roundTripParcelable; +import static android.app.timezonedetector.ShellCommandTestSupport.createShellCommandWithArgsAndOptions; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; +import android.os.ShellCommand; import android.os.TimestampedValue; import org.junit.Test; @@ -63,4 +65,36 @@ public class NetworkTimeSuggestionTest { NetworkTimeSuggestion rtSuggestion = roundTripParcelable(suggestion); assertEquals(suggestion.getDebugInfo(), rtSuggestion.getDebugInfo()); } + + @Test(expected = IllegalArgumentException.class) + public void testParseCommandLineArg_noReferenceTime() { + ShellCommand testShellCommand = createShellCommandWithArgsAndOptions( + "--unix_epoch_time 12345"); + NetworkTimeSuggestion.parseCommandLineArg(testShellCommand); + } + + @Test(expected = IllegalArgumentException.class) + public void testParseCommandLineArg_noUnixEpochTime() { + ShellCommand testShellCommand = createShellCommandWithArgsAndOptions( + "--reference_time 54321"); + NetworkTimeSuggestion.parseCommandLineArg(testShellCommand); + } + + @Test + public void testParseCommandLineArg_validSuggestion() { + ShellCommand testShellCommand = createShellCommandWithArgsAndOptions( + "--reference_time 54321 --unix_epoch_time 12345"); + TimestampedValue<Long> timeSignal = new TimestampedValue<>(54321L, 12345L); + NetworkTimeSuggestion expectedSuggestion = new NetworkTimeSuggestion(timeSignal); + NetworkTimeSuggestion actualSuggestion = + NetworkTimeSuggestion.parseCommandLineArg(testShellCommand); + assertEquals(expectedSuggestion, actualSuggestion); + } + + @Test(expected = IllegalArgumentException.class) + public void testParseCommandLineArg_unknownArgument() { + ShellCommand testShellCommand = createShellCommandWithArgsAndOptions( + "--reference_time 54321 --unix_epoch_time 12345 --bad_arg 0"); + NetworkTimeSuggestion.parseCommandLineArg(testShellCommand); + } } diff --git a/core/tests/coretests/src/android/app/timedetector/TelephonyTimeSuggestionTest.java b/core/tests/coretests/src/android/app/timedetector/TelephonyTimeSuggestionTest.java index cc7557977e80..bb995a852637 100644 --- a/core/tests/coretests/src/android/app/timedetector/TelephonyTimeSuggestionTest.java +++ b/core/tests/coretests/src/android/app/timedetector/TelephonyTimeSuggestionTest.java @@ -18,10 +18,12 @@ package android.app.timedetector; import static android.app.timezonedetector.ParcelableTestSupport.assertRoundTripParcelable; import static android.app.timezonedetector.ParcelableTestSupport.roundTripParcelable; +import static android.app.timezonedetector.ShellCommandTestSupport.createShellCommandWithArgsAndOptions; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; +import android.os.ShellCommand; import android.os.TimestampedValue; import org.junit.Test; @@ -95,4 +97,45 @@ public class TelephonyTimeSuggestionTest { assertEquals(suggestion1.getDebugInfo(), rtSuggestion1.getDebugInfo()); } } + + @Test(expected = IllegalArgumentException.class) + public void testParseCommandLineArg_noSlotIndex() { + ShellCommand testShellCommand = createShellCommandWithArgsAndOptions( + "--reference_time 54321 --unix_epoch_time 12345"); + TelephonyTimeSuggestion.parseCommandLineArg(testShellCommand); + } + + @Test(expected = IllegalArgumentException.class) + public void testParseCommandLineArg_noReferenceTime() { + ShellCommand testShellCommand = createShellCommandWithArgsAndOptions( + "--slot_index 0 --unix_epoch_time 12345"); + TelephonyTimeSuggestion.parseCommandLineArg(testShellCommand); + } + + @Test(expected = IllegalArgumentException.class) + public void testParseCommandLineArg_noUnixEpochTime() { + ShellCommand testShellCommand = createShellCommandWithArgsAndOptions( + "--slot_index 0 --reference_time 54321"); + TelephonyTimeSuggestion.parseCommandLineArg(testShellCommand); + } + + @Test + public void testParseCommandLineArg_validSuggestion() { + ShellCommand testShellCommand = createShellCommandWithArgsAndOptions( + "--slot_index 0 --reference_time 54321 --unix_epoch_time 12345"); + TelephonyTimeSuggestion expectedSuggestion = + new TelephonyTimeSuggestion.Builder(0) + .setUnixEpochTime(new TimestampedValue<>(54321L, 12345L)) + .build(); + TelephonyTimeSuggestion actualSuggestion = + TelephonyTimeSuggestion.parseCommandLineArg(testShellCommand); + assertEquals(expectedSuggestion, actualSuggestion); + } + + @Test(expected = IllegalArgumentException.class) + public void testParseCommandLineArg_unknownArgument() { + ShellCommand testShellCommand = createShellCommandWithArgsAndOptions( + "--slot_index 0 --reference_time 54321 --unix_epoch_time 12345 --bad_arg 0"); + TelephonyTimeSuggestion.parseCommandLineArg(testShellCommand); + } } diff --git a/core/tests/coretests/src/android/app/timezonedetector/ShellCommandTestSupport.java b/core/tests/coretests/src/android/app/timezonedetector/ShellCommandTestSupport.java index 8d8290c7bdc9..4efaed11168e 100644 --- a/core/tests/coretests/src/android/app/timezonedetector/ShellCommandTestSupport.java +++ b/core/tests/coretests/src/android/app/timezonedetector/ShellCommandTestSupport.java @@ -26,14 +26,14 @@ import java.util.Arrays; import java.util.List; /** Utility methods related to {@link ShellCommand} objects used in several tests. */ -final class ShellCommandTestSupport { +public final class ShellCommandTestSupport { private ShellCommandTestSupport() {} - static ShellCommand createShellCommandWithArgsAndOptions(String argsWithSpaces) { + public static ShellCommand createShellCommandWithArgsAndOptions(String argsWithSpaces) { return createShellCommandWithArgsAndOptions(Arrays.asList(argsWithSpaces.split(" "))); } - static ShellCommand createShellCommandWithArgsAndOptions(List<String> args) { + public static ShellCommand createShellCommandWithArgsAndOptions(List<String> args) { ShellCommand command = mock(ShellCommand.class); class ArgProvider { private int mCount; diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreBCWorkaroundProvider.java b/keystore/java/android/security/keystore2/AndroidKeyStoreBCWorkaroundProvider.java index 9ad6f3adbd33..6fff52a20062 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreBCWorkaroundProvider.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreBCWorkaroundProvider.java @@ -206,6 +206,8 @@ class AndroidKeyStoreBCWorkaroundProvider extends Provider { putSignatureImpl("NONEwithECDSA", PACKAGE_NAME + ".AndroidKeyStoreECDSASignatureSpi$NONE"); + putSignatureImpl("Ed25519", + PACKAGE_NAME + ".AndroidKeyStoreECDSASignatureSpi$Ed25519"); putSignatureImpl("SHA1withECDSA", PACKAGE_NAME + ".AndroidKeyStoreECDSASignatureSpi$SHA1"); put("Alg.Alias.Signature.ECDSA", "SHA1withECDSA"); diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreECDSASignatureSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreECDSASignatureSpi.java index 8289671de212..5216a908826b 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreECDSASignatureSpi.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreECDSASignatureSpi.java @@ -29,7 +29,10 @@ import libcore.util.EmptyArray; import java.io.ByteArrayOutputStream; import java.security.InvalidKeyException; import java.security.SignatureSpi; +import java.security.spec.NamedParameterSpec; +import java.util.Arrays; import java.util.List; +import java.util.Set; /** * Base class for {@link SignatureSpi} providing Android KeyStore backed ECDSA signatures. @@ -37,6 +40,10 @@ import java.util.List; * @hide */ abstract class AndroidKeyStoreECDSASignatureSpi extends AndroidKeyStoreSignatureSpiBase { + private static final Set<String> ACCEPTED_SIGNING_SCHEMES = Set.of( + KeyProperties.KEY_ALGORITHM_EC.toLowerCase(), + NamedParameterSpec.ED25519.getName().toLowerCase(), + "eddsa"); public final static class NONE extends AndroidKeyStoreECDSASignatureSpi { public NONE() { @@ -114,6 +121,18 @@ abstract class AndroidKeyStoreECDSASignatureSpi extends AndroidKeyStoreSignature } } + public static final class Ed25519 extends AndroidKeyStoreECDSASignatureSpi { + public Ed25519() { + // Ed25519 uses an internal digest system. + super(KeymasterDefs.KM_DIGEST_NONE); + } + + @Override + protected String getAlgorithm() { + return NamedParameterSpec.ED25519.getName(); + } + } + public final static class SHA1 extends AndroidKeyStoreECDSASignatureSpi { public SHA1() { super(KeymasterDefs.KM_DIGEST_SHA1); @@ -174,9 +193,10 @@ abstract class AndroidKeyStoreECDSASignatureSpi extends AndroidKeyStoreSignature @Override protected final void initKey(AndroidKeyStoreKey key) throws InvalidKeyException { - if (!KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(key.getAlgorithm())) { + if (!ACCEPTED_SIGNING_SCHEMES.contains(key.getAlgorithm().toLowerCase())) { throw new InvalidKeyException("Unsupported key algorithm: " + key.getAlgorithm() - + ". Only" + KeyProperties.KEY_ALGORITHM_EC + " supported"); + + ". Only" + Arrays.toString(ACCEPTED_SIGNING_SCHEMES.stream().toArray()) + + " supported"); } long keySizeBits = -1; diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreEdECPrivateKey.java b/keystore/java/android/security/keystore2/AndroidKeyStoreEdECPrivateKey.java new file mode 100644 index 000000000000..4855ad0f7293 --- /dev/null +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreEdECPrivateKey.java @@ -0,0 +1,46 @@ +/* + * 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. + */ + +package android.security.keystore2; + +import android.annotation.NonNull; +import android.security.KeyStoreSecurityLevel; +import android.system.keystore2.Authorization; +import android.system.keystore2.KeyDescriptor; + +import java.security.PrivateKey; +import java.security.interfaces.EdECKey; +import java.security.spec.NamedParameterSpec; + +/** + * EdEC private key (instance of {@link PrivateKey} and {@link EdECKey}) backed by keystore. + * + * @hide + */ +public class AndroidKeyStoreEdECPrivateKey extends AndroidKeyStorePrivateKey implements EdECKey { + public AndroidKeyStoreEdECPrivateKey( + @NonNull KeyDescriptor descriptor, long keyId, + @NonNull Authorization[] authorizations, + @NonNull String algorithm, + @NonNull KeyStoreSecurityLevel securityLevel) { + super(descriptor, keyId, authorizations, algorithm, securityLevel); + } + + @Override + public NamedParameterSpec getParams() { + return NamedParameterSpec.ED25519; + } +} diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreEdECPublicKey.java b/keystore/java/android/security/keystore2/AndroidKeyStoreEdECPublicKey.java new file mode 100644 index 000000000000..642e08813291 --- /dev/null +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreEdECPublicKey.java @@ -0,0 +1,145 @@ +/* + * 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. + */ + +package android.security.keystore2; + +import android.annotation.NonNull; +import android.security.KeyStoreSecurityLevel; +import android.system.keystore2.KeyDescriptor; +import android.system.keystore2.KeyMetadata; + +import java.math.BigInteger; +import java.security.interfaces.EdECPublicKey; +import java.security.spec.EdECPoint; +import java.security.spec.NamedParameterSpec; +import java.util.Arrays; +import java.util.Objects; + +/** + * {@link EdECPublicKey} backed by keystore. + * + * @hide + */ +public class AndroidKeyStoreEdECPublicKey extends AndroidKeyStorePublicKey + implements EdECPublicKey { + /** + * DER sequence, as defined in https://datatracker.ietf.org/doc/html/rfc8410#section-4 and + * https://datatracker.ietf.org/doc/html/rfc5280#section-4.1. + * SEQUENCE (2 elem) + * SEQUENCE (1 elem) + * OBJECT IDENTIFIER 1.3.101.112 curveEd25519 (EdDSA 25519 signature algorithm) + * as defined in https://datatracker.ietf.org/doc/html/rfc8410#section-3 + * BIT STRING (256 bit) as defined in + * https://datatracker.ietf.org/doc/html/rfc8032#section-5.1.2 + */ + private static final byte[] DER_KEY_PREFIX = new byte[] { + 0x30, + 0x2a, + 0x30, + 0x05, + 0x06, + 0x03, + 0x2b, + 0x65, + 0x70, + 0x03, + 0x21, + 0x00, + }; + private static final int ED25519_KEY_SIZE_BYTES = 32; + + private byte[] mEncodedKey; + private EdECPoint mPoint; + + public AndroidKeyStoreEdECPublicKey( + @NonNull KeyDescriptor descriptor, + @NonNull KeyMetadata metadata, + @NonNull String algorithm, + @NonNull KeyStoreSecurityLevel iSecurityLevel, + @NonNull byte[] encodedKey) { + super(descriptor, metadata, encodedKey, algorithm, iSecurityLevel); + mEncodedKey = encodedKey; + + int preambleLength = matchesPreamble(DER_KEY_PREFIX, encodedKey); + if (preambleLength == 0) { + throw new IllegalArgumentException("Key size is not correct size"); + } + + mPoint = pointFromKeyByteArray( + Arrays.copyOfRange(encodedKey, preambleLength, encodedKey.length)); + } + + @Override + AndroidKeyStorePrivateKey getPrivateKey() { + return new AndroidKeyStoreEdECPrivateKey( + getUserKeyDescriptor(), + getKeyIdDescriptor().nspace, + getAuthorizations(), + "EdDSA", + getSecurityLevel()); + } + + @Override + public NamedParameterSpec getParams() { + return NamedParameterSpec.ED25519; + } + + @Override + public EdECPoint getPoint() { + return mPoint; + } + + private static int matchesPreamble(byte[] preamble, byte[] encoded) { + if (encoded.length != (preamble.length + ED25519_KEY_SIZE_BYTES)) { + return 0; + } + if (Arrays.compare(preamble, Arrays.copyOf(encoded, preamble.length)) != 0) { + return 0; + } + return preamble.length; + } + + private static EdECPoint pointFromKeyByteArray(byte[] coordinates) { + Objects.requireNonNull(coordinates); + + // Oddity of the key is the most-significant bit of the last byte. + boolean isOdd = (0x80 & coordinates[coordinates.length - 1]) != 0; + // Zero out the oddity bit. + coordinates[coordinates.length - 1] &= (byte) 0x7f; + // Representation of Y is in little-endian, according to rfc8032 section-3.1. + reverse(coordinates); + // The integer representing Y starts from the first bit in the coordinates array. + BigInteger y = new BigInteger(1, coordinates); + return new EdECPoint(isOdd, y); + } + + private static void reverse(byte[] coordinateArray) { + int start = 0; + int end = coordinateArray.length - 1; + while (start < end) { + byte tmp = coordinateArray[start]; + coordinateArray[start] = coordinateArray[end]; + coordinateArray[end] = tmp; + start++; + end--; + } + } + + @Override + public byte[] getEncoded() { + return mEncodedKey.clone(); + } +} diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyAgreementSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyAgreementSpi.java index fc963a88c4d1..b1338d164055 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyAgreementSpi.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyAgreementSpi.java @@ -61,6 +61,17 @@ public class AndroidKeyStoreKeyAgreementSpi extends KeyAgreementSpi } } + /** + * X25519 key agreement support. + * + * @hide + */ + public static class XDH extends AndroidKeyStoreKeyAgreementSpi { + public XDH() { + super(Algorithm.EC); + } + } + private final int mKeymintAlgorithm; // Fields below are populated by engineInit and should be preserved after engineDoFinal. diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java index d31499e8b36d..9947d34495ab 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java @@ -104,6 +104,7 @@ public class AndroidKeyStoreProvider extends Provider { // javax.crypto.KeyAgreement put("KeyAgreement.ECDH", PACKAGE_NAME + ".AndroidKeyStoreKeyAgreementSpi$ECDH"); + put("KeyAgreement.XDH", PACKAGE_NAME + ".AndroidKeyStoreKeyAgreementSpi$XDH"); // java.security.SecretKeyFactory putSecretKeyFactoryImpl("AES"); @@ -224,7 +225,6 @@ public class AndroidKeyStoreProvider extends Provider { String jcaKeyAlgorithm = publicKey.getAlgorithm(); - KeyStoreSecurityLevel securityLevel = iSecurityLevel; if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(jcaKeyAlgorithm)) { return new AndroidKeyStoreECPublicKey(descriptor, metadata, iSecurityLevel, (ECPublicKey) publicKey); @@ -232,11 +232,12 @@ public class AndroidKeyStoreProvider extends Provider { return new AndroidKeyStoreRSAPublicKey(descriptor, metadata, iSecurityLevel, (RSAPublicKey) publicKey); } else if (ED25519_OID.equalsIgnoreCase(jcaKeyAlgorithm)) { - //TODO(b/214203951) missing classes in conscrypt - throw new ProviderException("Curve " + ED25519_OID + " not supported yet"); + final byte[] publicKeyEncoded = publicKey.getEncoded(); + return new AndroidKeyStoreEdECPublicKey(descriptor, metadata, ED25519_OID, + iSecurityLevel, publicKeyEncoded); } else if (X25519_ALIAS.equalsIgnoreCase(jcaKeyAlgorithm)) { - //TODO(b/214203951) missing classes in conscrypt - throw new ProviderException("Curve " + X25519_ALIAS + " not supported yet"); + return new AndroidKeyStoreXDHPublicKey(descriptor, metadata, X25519_ALIAS, + iSecurityLevel, publicKey.getEncoded()); } else { throw new ProviderException("Unsupported Android Keystore public key algorithm: " + jcaKeyAlgorithm); diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreXDHPrivateKey.java b/keystore/java/android/security/keystore2/AndroidKeyStoreXDHPrivateKey.java new file mode 100644 index 000000000000..42589640d2b7 --- /dev/null +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreXDHPrivateKey.java @@ -0,0 +1,47 @@ +/* + * 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. + */ + +package android.security.keystore2; + +import android.annotation.NonNull; +import android.security.KeyStoreSecurityLevel; +import android.system.keystore2.Authorization; +import android.system.keystore2.KeyDescriptor; + +import java.security.PrivateKey; +import java.security.interfaces.EdECKey; +import java.security.spec.NamedParameterSpec; + +/** + * X25519 Private Key backed by Keystore. + * instance of {@link PrivateKey} and {@link EdECKey} + * + * @hide + */ +public class AndroidKeyStoreXDHPrivateKey extends AndroidKeyStorePrivateKey implements EdECKey { + public AndroidKeyStoreXDHPrivateKey( + @NonNull KeyDescriptor descriptor, long keyId, + @NonNull Authorization[] authorizations, + @NonNull String algorithm, + @NonNull KeyStoreSecurityLevel securityLevel) { + super(descriptor, keyId, authorizations, algorithm, securityLevel); + } + + @Override + public NamedParameterSpec getParams() { + return NamedParameterSpec.X25519; + } +} diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreXDHPublicKey.java b/keystore/java/android/security/keystore2/AndroidKeyStoreXDHPublicKey.java new file mode 100644 index 000000000000..9f3df3d72d86 --- /dev/null +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreXDHPublicKey.java @@ -0,0 +1,120 @@ +/* + * 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. + */ + +package android.security.keystore2; + +import android.annotation.NonNull; +import android.security.KeyStoreSecurityLevel; +import android.system.keystore2.KeyDescriptor; +import android.system.keystore2.KeyMetadata; + +import java.math.BigInteger; +import java.security.interfaces.XECPublicKey; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.NamedParameterSpec; +import java.util.Arrays; + +/** + * {@link XECPublicKey} backed by keystore. + * This class re-implements Conscrypt's OpenSSLX25519PublicKey. The reason is that + * OpenSSLX25519PublicKey does not implement XECPublicKey and is not a part of Conscrypt's public + * interface so it cannot be referred to. + * + * So the functionality is duplicated here until (likely Android U) one of the things mentioned + * above is fixed. + * + * @hide + */ +public class AndroidKeyStoreXDHPublicKey extends AndroidKeyStorePublicKey implements XECPublicKey { + private static final byte[] X509_PREAMBLE = new byte[] { + 0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6e, 0x03, 0x21, 0x00, + }; + + private static final byte[] X509_PREAMBLE_WITH_NULL = new byte[] { + 0x30, 0x2C, 0x30, 0x07, 0x06, 0x03, 0x2B, 0x65, 0x6E, 0x05, 0x00, 0x03, 0x21, 0x00, + }; + + private static final int X25519_KEY_SIZE_BYTES = 32; + + private final byte[] mEncodedKey; + private final int mPreambleLength; + + public AndroidKeyStoreXDHPublicKey( + @NonNull KeyDescriptor descriptor, + @NonNull KeyMetadata metadata, + @NonNull String algorithm, + @NonNull KeyStoreSecurityLevel iSecurityLevel, + @NonNull byte[] encodedKey) { + super(descriptor, metadata, encodedKey, algorithm, iSecurityLevel); + mEncodedKey = encodedKey; + if (mEncodedKey == null) { + throw new IllegalArgumentException("empty encoded key."); + } + + mPreambleLength = matchesPreamble(X509_PREAMBLE, mEncodedKey) | matchesPreamble( + X509_PREAMBLE_WITH_NULL, mEncodedKey); + if (mPreambleLength == 0) { + throw new IllegalArgumentException("Key size is not correct size"); + } + } + + private static int matchesPreamble(byte[] preamble, byte[] encoded) { + if (encoded.length != (preamble.length + X25519_KEY_SIZE_BYTES)) { + return 0; + } + + if (Arrays.compare(preamble, 0, preamble.length, encoded, 0, preamble.length) != 0) { + return 0; + } + return preamble.length; + } + + @Override + AndroidKeyStorePrivateKey getPrivateKey() { + return new AndroidKeyStoreXDHPrivateKey( + getUserKeyDescriptor(), + getKeyIdDescriptor().nspace, + getAuthorizations(), + "x25519", + getSecurityLevel()); + } + + @Override + public BigInteger getU() { + return new BigInteger(Arrays.copyOfRange(mEncodedKey, mPreambleLength, mEncodedKey.length)); + } + + @Override + public byte[] getEncoded() { + return mEncodedKey.clone(); + } + + @Override + public String getAlgorithm() { + return "XDH"; + } + + @Override + public String getFormat() { + return "x.509"; + } + + @Override + public AlgorithmParameterSpec getParams() { + return NamedParameterSpec.X25519; + } +} + diff --git a/keystore/tests/src/android/security/keystore2/AndroidKeyStoreEdECPublicKeyTest.java b/keystore/tests/src/android/security/keystore2/AndroidKeyStoreEdECPublicKeyTest.java new file mode 100644 index 000000000000..5bd5797859c9 --- /dev/null +++ b/keystore/tests/src/android/security/keystore2/AndroidKeyStoreEdECPublicKeyTest.java @@ -0,0 +1,123 @@ +/* + * 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. + */ + +package android.security.keystore2; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; + +import android.security.KeyStoreSecurityLevel; +import android.system.keystore2.Authorization; +import android.system.keystore2.Domain; +import android.system.keystore2.KeyDescriptor; +import android.system.keystore2.KeyMetadata; + +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; + +import java.math.BigInteger; +import java.util.Base64; + +@RunWith(AndroidJUnit4.class) +public class AndroidKeyStoreEdECPublicKeyTest { + private static KeyDescriptor descriptor() { + final KeyDescriptor keyDescriptor = new KeyDescriptor(); + keyDescriptor.alias = "key"; + keyDescriptor.blob = null; + keyDescriptor.domain = Domain.APP; + keyDescriptor.nspace = -1; + return keyDescriptor; + } + + private static KeyMetadata metadata(byte[] cert, byte[] certChain) { + KeyMetadata metadata = new KeyMetadata(); + metadata.authorizations = new Authorization[0]; + metadata.certificate = cert; + metadata.certificateChain = certChain; + metadata.key = descriptor(); + metadata.modificationTimeMs = 0; + metadata.keySecurityLevel = 1; + return metadata; + } + + @Mock + private KeyStoreSecurityLevel mKeystoreSecurityLevel; + + private static class EdECTestVector { + public final byte[] encodedKeyBytes; + public final boolean isOdd; + public final BigInteger yValue; + + EdECTestVector(String b64KeyBytes, boolean isOdd, String yValue) { + this.encodedKeyBytes = Base64.getDecoder().decode(b64KeyBytes); + this.isOdd = isOdd; + this.yValue = new BigInteger(yValue); + } + } + + private static final EdECTestVector[] ED_EC_TEST_VECTORS = new EdECTestVector[]{ + new EdECTestVector("MCowBQYDK2VwAyEADE+wvQqNHxaERPhAZ0rCFlgFbfWLs/YonPXdSTw0VSo=", + false, + "19147682157189290216699341180089409126316261024914226007941553249095116672780" + ), + new EdECTestVector("MCowBQYDK2VwAyEA/0E1IRNzGj85Ot/TPeXqifkqTkdk4voleH0hIq59D9w=", + true, + "41640152188550647350742178040529506688513911269563908889464821205156322689535" + ), + new EdECTestVector("MCowBQYDK2VwAyEAunOvGuenetl9GQSXGVo5L3RIr4OOIpFIv/Zre8qTc/8=", + true, + "57647939198144376128225770417635248407428273266444593100194116168980378907578" + ), + new EdECTestVector("MCowBQYDK2VwAyEA2hHqaZ5IolswN1Yd58Y4hzhmUMCCqc4PW5A/SFLmTX8=", + false, + "57581368614046789120409806291852629847774713088410311752049592044694364885466" + ), + }; + + @Test + public void testParsingOfValidKeys() { + for (EdECTestVector testVector : ED_EC_TEST_VECTORS) { + AndroidKeyStoreEdECPublicKey pkey = new AndroidKeyStoreEdECPublicKey(descriptor(), + metadata(null, null), "EdDSA", mKeystoreSecurityLevel, + testVector.encodedKeyBytes); + + assertEquals(pkey.getPoint().isXOdd(), testVector.isOdd); + assertEquals(pkey.getPoint().getY(), testVector.yValue); + } + } + + @Test + public void testFailedParsingOfKeysWithDifferentOid() { + final byte[] testVectorWithIncorrectOid = Base64.getDecoder().decode( + "MCowBQYDLGVwAyEADE+wvQqNHxaERPhAZ0rCFlgFbfWLs/YonPXdSTw0VSo="); + assertThrows("OID should be unrecognized", IllegalArgumentException.class, + () -> new AndroidKeyStoreEdECPublicKey(descriptor(), metadata(null, null), "EdDSA", + mKeystoreSecurityLevel, testVectorWithIncorrectOid)); + } + + @Test + public void testFailedParsingOfKeysWithWrongSize() { + final byte[] testVectorWithIncorrectKeySize = Base64.getDecoder().decode( + "MCwwBQYDK2VwAyMADE+wvQqNHxaERPhAZ0rCFlgFbfWLs/YonPXdSTw0VSrOzg=="); + assertThrows("Key length should be invalid", IllegalArgumentException.class, + () -> new AndroidKeyStoreEdECPublicKey(descriptor(), metadata(null, null), "EdDSA", + mKeystoreSecurityLevel, testVectorWithIncorrectKeySize)); + } +} + diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java index 050ae7268ef2..66e2c413312e 100644 --- a/media/java/android/media/MediaFormat.java +++ b/media/java/android/media/MediaFormat.java @@ -230,9 +230,10 @@ public final class MediaFormat { /** * A key describing the log session ID for MediaCodec. The log session ID is a random 32-byte * hexadecimal string that is used to associate metrics from multiple media codec instances - * to the same playback or recording session. + * to the same playback or recording session. The value is created as + * {@link android.media.metrics.LogSessionId LogSessionId}. Sessions are created in + * {@link android.media.metrics.MediaMetricsManager MediaMetricsManager}. * The associated value is a string. - * @hide */ public static final String LOG_SESSION_ID = "log-session-id"; diff --git a/packages/SettingsLib/ActionBarShadow/Android.bp b/packages/SettingsLib/ActionBarShadow/Android.bp index 4a07d49fcde5..2c86201591fb 100644 --- a/packages/SettingsLib/ActionBarShadow/Android.bp +++ b/packages/SettingsLib/ActionBarShadow/Android.bp @@ -20,4 +20,8 @@ android_library { sdk_version: "system_current", min_sdk_version: "28", + apex_available: [ + "//apex_available:platform", + "com.android.permission", + ], } diff --git a/packages/SettingsLib/AppPreference/Android.bp b/packages/SettingsLib/AppPreference/Android.bp index 1817a77981a9..122f60672b2a 100644 --- a/packages/SettingsLib/AppPreference/Android.bp +++ b/packages/SettingsLib/AppPreference/Android.bp @@ -20,4 +20,8 @@ android_library { ], sdk_version: "system_current", min_sdk_version: "21", + apex_available: [ + "//apex_available:platform", + "com.android.permission", + ], } diff --git a/packages/SettingsLib/BarChartPreference/Android.bp b/packages/SettingsLib/BarChartPreference/Android.bp index 4f6537334770..5c5da9827e61 100644 --- a/packages/SettingsLib/BarChartPreference/Android.bp +++ b/packages/SettingsLib/BarChartPreference/Android.bp @@ -19,4 +19,8 @@ android_library { sdk_version: "system_current", min_sdk_version: "21", + apex_available: [ + "//apex_available:platform", + "com.android.permission", + ], } diff --git a/packages/SettingsLib/HelpUtils/Android.bp b/packages/SettingsLib/HelpUtils/Android.bp index 5826047b9f52..aea51b1bba2d 100644 --- a/packages/SettingsLib/HelpUtils/Android.bp +++ b/packages/SettingsLib/HelpUtils/Android.bp @@ -19,4 +19,8 @@ android_library { sdk_version: "system_current", min_sdk_version: "21", + apex_available: [ + "//apex_available:platform", + "com.android.permission", + ], } diff --git a/packages/SettingsLib/LayoutPreference/Android.bp b/packages/SettingsLib/LayoutPreference/Android.bp index 8a4e53d80a7c..aaffdc922875 100644 --- a/packages/SettingsLib/LayoutPreference/Android.bp +++ b/packages/SettingsLib/LayoutPreference/Android.bp @@ -14,9 +14,13 @@ android_library { resource_dirs: ["res"], static_libs: [ - "androidx.preference_preference", + "androidx.preference_preference", ], sdk_version: "system_current", min_sdk_version: "21", + apex_available: [ + "//apex_available:platform", + "com.android.permission", + ], } diff --git a/packages/SettingsLib/ProgressBar/Android.bp b/packages/SettingsLib/ProgressBar/Android.bp index b5bc8f77045b..fb3c4e6efd90 100644 --- a/packages/SettingsLib/ProgressBar/Android.bp +++ b/packages/SettingsLib/ProgressBar/Android.bp @@ -15,4 +15,8 @@ android_library { sdk_version: "system_current", min_sdk_version: "21", + apex_available: [ + "//apex_available:platform", + "com.android.permission", + ], } diff --git a/packages/SettingsLib/RestrictedLockUtils/Android.bp b/packages/SettingsLib/RestrictedLockUtils/Android.bp index c0623edabefe..a7dcf8d52915 100644 --- a/packages/SettingsLib/RestrictedLockUtils/Android.bp +++ b/packages/SettingsLib/RestrictedLockUtils/Android.bp @@ -19,4 +19,8 @@ android_library { sdk_version: "system_current", min_sdk_version: "21", + apex_available: [ + "//apex_available:platform", + "com.android.permission", + ], } diff --git a/packages/SettingsLib/SearchWidget/Android.bp b/packages/SettingsLib/SearchWidget/Android.bp index b7367b4a10a7..5aaee2afc069 100644 --- a/packages/SettingsLib/SearchWidget/Android.bp +++ b/packages/SettingsLib/SearchWidget/Android.bp @@ -14,4 +14,8 @@ android_library { resource_dirs: ["res"], sdk_version: "system_current", min_sdk_version: "21", + apex_available: [ + "//apex_available:platform", + "com.android.permission", + ], } diff --git a/packages/SettingsLib/SettingsTheme/Android.bp b/packages/SettingsLib/SettingsTheme/Android.bp index 73459c277df1..da01f62b97d4 100644 --- a/packages/SettingsLib/SettingsTheme/Android.bp +++ b/packages/SettingsLib/SettingsTheme/Android.bp @@ -13,13 +13,14 @@ android_library { resource_dirs: ["res"], static_libs: [ - "androidx.preference_preference", - ], + "androidx.preference_preference", + ], sdk_version: "system_current", min_sdk_version: "21", apex_available: [ "//apex_available:platform", "com.android.cellbroadcast", + "com.android.permission", ], } diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index ff4c2c63f8b4..c4d4261ba080 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -478,6 +478,12 @@ <uses-permission android:name="android.permission.MANAGE_TIME_AND_ZONE_DETECTION" /> <uses-permission android:name="android.permission.SUGGEST_EXTERNAL_TIME" /> + <!-- Permissions used for manual testing of time detection behavior. --> + <uses-permission android:name="android.permission.SUGGEST_MANUAL_TIME" /> + <uses-permission android:name="android.permission.SUGGEST_TELEPHONY_TIME" /> + <uses-permission android:name="android.permission.SUGGEST_NETWORK_TIME" /> + <uses-permission android:name="android.permission.SUGGEST_GNSS_TIME" /> + <!-- Permission required for CTS test - android.server.biometrics --> <uses-permission android:name="android.permission.USE_BIOMETRIC" /> diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java index 9676a57b2df9..91c7a24afaf7 100644 --- a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java @@ -376,7 +376,7 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon Log.w(TAG, String.format("onActiveChanged(%d,%d,%s,%s,%d,%d)", code, uid, packageName, Boolean.toString(active), attributionChainId, attributionFlags)); } - if (attributionChainId != AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE + if (active && attributionChainId != AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE && attributionFlags != AppOpsManager.ATTRIBUTION_FLAGS_NONE && (attributionFlags & AppOpsManager.ATTRIBUTION_FLAG_ACCESSOR) == 0 && (attributionFlags & AppOpsManager.ATTRIBUTION_FLAG_TRUSTED) == 0) { diff --git a/services/core/OWNERS b/services/core/OWNERS deleted file mode 100644 index 88d0b61a2ab6..000000000000 --- a/services/core/OWNERS +++ /dev/null @@ -1 +0,0 @@ -per-file Android.bp = file:platform/build/soong:/OWNERS diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java index 406ff9b00686..a81699fa82c3 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java +++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java @@ -1202,8 +1202,11 @@ import java.util.concurrent.atomic.AtomicBoolean; break; case MSG_L_SET_BT_ACTIVE_DEVICE: synchronized (mDeviceStateLock) { - mDeviceInventory.onSetBtActiveDevice((BtDeviceInfo) msg.obj, - mAudioService.getBluetoothContextualVolumeStream()); + BtDeviceInfo btInfo = (BtDeviceInfo) msg.obj; + mDeviceInventory.onSetBtActiveDevice(btInfo, + (btInfo.mProfile != BluetoothProfile.LE_AUDIO || btInfo.mIsLeOutput) + ? mAudioService.getBluetoothContextualVolumeStream() + : AudioSystem.STREAM_DEFAULT); } break; case MSG_BT_HEADSET_CNCT_FAILED: diff --git a/services/core/java/com/android/server/clipboard/EmulatorClipboardMonitor.java b/services/core/java/com/android/server/clipboard/EmulatorClipboardMonitor.java index 28c7cad3b184..ab3b2506f5ac 100644 --- a/services/core/java/com/android/server/clipboard/EmulatorClipboardMonitor.java +++ b/services/core/java/com/android/server/clipboard/EmulatorClipboardMonitor.java @@ -18,6 +18,7 @@ package com.android.server.clipboard; import android.annotation.Nullable; import android.content.ClipData; +import android.os.PersistableBundle; import android.os.SystemProperties; import android.system.ErrnoException; import android.system.Os; @@ -25,6 +26,7 @@ import android.system.OsConstants; import android.system.VmSocketAddress; import android.util.Slog; +import java.io.EOFException; import java.io.FileDescriptor; import java.io.InterruptedIOException; import java.net.SocketException; @@ -58,11 +60,11 @@ class EmulatorClipboardMonitor implements Consumer<ClipData> { return mPipe; } - private synchronized boolean openPipe() { - if (mPipe != null) { - return true; - } + private synchronized void setPipeFD(final FileDescriptor fd) { + mPipe = fd; + } + private static FileDescriptor openPipeImpl() { try { final FileDescriptor fd = Os.socket(OsConstants.AF_VSOCK, OsConstants.SOCK_STREAM, 0); @@ -70,39 +72,42 @@ class EmulatorClipboardMonitor implements Consumer<ClipData> { Os.connect(fd, new VmSocketAddress(HOST_PORT, OsConstants.VMADDR_CID_HOST)); final byte[] handshake = createOpenHandshake(); - Os.write(fd, handshake, 0, handshake.length); - mPipe = fd; - return true; + writeFully(fd, handshake, 0, handshake.length); + return fd; } catch (ErrnoException | SocketException | InterruptedIOException e) { Os.close(fd); } } catch (ErrnoException e) { } - return false; + return null; } - private synchronized void closePipe() { - try { - final FileDescriptor fd = mPipe; - mPipe = null; - if (fd != null) { - Os.close(fd); - } - } catch (ErrnoException ignore) { + private static FileDescriptor openPipe() throws InterruptedException { + FileDescriptor fd = openPipeImpl(); + + // There's no guarantee that QEMU pipes will be ready at the moment + // this method is invoked. We simply try to get the pipe open and + // retry on failure indefinitely. + while (fd == null) { + Thread.sleep(100); + fd = openPipeImpl(); } + + return fd; } - private byte[] receiveMessage() throws ErrnoException, InterruptedIOException { + private static byte[] receiveMessage(final FileDescriptor fd) throws ErrnoException, + InterruptedIOException, EOFException { final byte[] lengthBits = new byte[4]; - Os.read(mPipe, lengthBits, 0, lengthBits.length); + readFully(fd, lengthBits, 0, lengthBits.length); final ByteBuffer bb = ByteBuffer.wrap(lengthBits); bb.order(ByteOrder.LITTLE_ENDIAN); final int msgLen = bb.getInt(); final byte[] msg = new byte[msgLen]; - Os.read(mPipe, msg, 0, msg.length); + readFully(fd, msg, 0, msg.length); return msg; } @@ -115,35 +120,46 @@ class EmulatorClipboardMonitor implements Consumer<ClipData> { bb.order(ByteOrder.LITTLE_ENDIAN); bb.putInt(msg.length); - Os.write(fd, lengthBits, 0, lengthBits.length); - Os.write(fd, msg, 0, msg.length); + writeFully(fd, lengthBits, 0, lengthBits.length); + writeFully(fd, msg, 0, msg.length); } EmulatorClipboardMonitor(final Consumer<ClipData> setAndroidClipboard) { this.mHostMonitorThread = new Thread(() -> { + FileDescriptor fd = null; + while (!Thread.interrupted()) { try { - // There's no guarantee that QEMU pipes will be ready at the moment - // this method is invoked. We simply try to get the pipe open and - // retry on failure indefinitely. - while (!openPipe()) { - Thread.sleep(100); + if (fd == null) { + fd = openPipe(); + setPipeFD(fd); } - final byte[] receivedData = receiveMessage(); + final byte[] receivedData = receiveMessage(fd); final String str = new String(receivedData); final ClipData clip = new ClipData("host clipboard", new String[]{"text/plain"}, new ClipData.Item(str)); + final PersistableBundle bundle = new PersistableBundle(); + bundle.putBoolean("com.android.systemui.SUPPRESS_CLIPBOARD_OVERLAY", true); + clip.getDescription().setExtras(bundle); if (LOG_CLIBOARD_ACCESS) { Slog.i(TAG, "Setting the guest clipboard to '" + str + "'"); } setAndroidClipboard.accept(clip); - } catch (ErrnoException | InterruptedIOException e) { - closePipe(); - } catch (InterruptedException | IllegalArgumentException e) { + } catch (ErrnoException | EOFException | InterruptedIOException + | InterruptedException e) { + setPipeFD(null); + + try { + Os.close(fd); + } catch (ErrnoException e2) { + // ignore + } + + fd = null; } } }); @@ -153,33 +169,70 @@ class EmulatorClipboardMonitor implements Consumer<ClipData> { @Override public void accept(final @Nullable ClipData clip) { + final FileDescriptor fd = getPipeFD(); + if (fd != null) { + setHostClipboard(fd, getClipString(clip)); + } + } + + private String getClipString(final @Nullable ClipData clip) { if (clip == null) { - setHostClipboardImpl(""); - } else if (clip.getItemCount() > 0) { - final CharSequence text = clip.getItemAt(0).getText(); - if (text != null) { - setHostClipboardImpl(text.toString()); - } + return ""; + } + + if (clip.getItemCount() == 0) { + return ""; } + + final CharSequence text = clip.getItemAt(0).getText(); + if (text == null) { + return ""; + } + + return text.toString(); } - private void setHostClipboardImpl(final String value) { - final FileDescriptor pipeFD = getPipeFD(); + private static void setHostClipboard(final FileDescriptor fd, final String value) { + Thread t = new Thread(() -> { + if (LOG_CLIBOARD_ACCESS) { + Slog.i(TAG, "Setting the host clipboard to '" + value + "'"); + } - if (pipeFD != null) { - Thread t = new Thread(() -> { - if (LOG_CLIBOARD_ACCESS) { - Slog.i(TAG, "Setting the host clipboard to '" + value + "'"); - } + try { + sendMessage(fd, value.getBytes()); + } catch (ErrnoException | InterruptedIOException e) { + Slog.e(TAG, "Failed to set host clipboard " + e.getMessage()); + } catch (IllegalArgumentException e) { + } + }); + t.start(); + } - try { - sendMessage(pipeFD, value.getBytes()); - } catch (ErrnoException | InterruptedIOException e) { - Slog.e(TAG, "Failed to set host clipboard " + e.getMessage()); - } catch (IllegalArgumentException e) { - } - }); - t.start(); + private static void readFully(final FileDescriptor fd, + final byte[] buf, int offset, int size) + throws ErrnoException, InterruptedIOException, EOFException { + while (size > 0) { + final int r = Os.read(fd, buf, offset, size); + if (r > 0) { + offset += r; + size -= r; + } else { + throw new EOFException(); + } + } + } + + private static void writeFully(final FileDescriptor fd, + final byte[] buf, int offset, int size) + throws ErrnoException, InterruptedIOException { + while (size > 0) { + final int r = Os.write(fd, buf, offset, size); + if (r > 0) { + offset += r; + size -= r; + } else { + throw new ErrnoException("write", OsConstants.EIO); + } } } } diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index d07f151f25bd..f0f187098bc5 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -1621,11 +1621,19 @@ public class Vpn { } // Note: Return type guarantees results are deduped and sorted, which callers require. + // This method also adds the SDK sandbox UIDs corresponding to the applications by default, + // since apps are generally not aware of them, yet they should follow the VPN configuration + // of the app they belong to. private SortedSet<Integer> getAppsUids(List<String> packageNames, int userId) { SortedSet<Integer> uids = new TreeSet<>(); for (String app : packageNames) { int uid = getAppUid(app, userId); if (uid != -1) uids.add(uid); + // TODO(b/230548427): Remove SDK check once VPN related stuff are decoupled from + // ConnectivityServiceTest. + if (Process.isApplicationUid(uid) && SdkLevel.isAtLeastT()) { + uids.add(Process.toSdkSandboxUid(uid)); + } } return uids; } diff --git a/services/core/java/com/android/server/timedetector/EnvironmentImpl.java b/services/core/java/com/android/server/timedetector/EnvironmentImpl.java index 7649958fe6c9..9d263516db3a 100644 --- a/services/core/java/com/android/server/timedetector/EnvironmentImpl.java +++ b/services/core/java/com/android/server/timedetector/EnvironmentImpl.java @@ -22,6 +22,7 @@ import android.app.AlarmManager; import android.content.ContentResolver; import android.content.Context; import android.database.ContentObserver; +import android.os.Build; import android.os.Handler; import android.os.PowerManager; import android.os.SystemClock; @@ -166,6 +167,11 @@ final class EnvironmentImpl implements TimeDetectorStrategyImpl.Environment { mWakeLock.release(); } + @Override + public boolean deviceHasY2038Issue() { + return Build.SUPPORTED_32_BIT_ABIS.length > 0; + } + private void checkWakeLockHeld() { if (!mWakeLock.isHeld()) { Slog.wtf(LOG_TAG, "WakeLock " + mWakeLock + " not held"); diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorShellCommand.java b/services/core/java/com/android/server/timedetector/TimeDetectorShellCommand.java index 721986bc6e93..cc5e6fe433fa 100644 --- a/services/core/java/com/android/server/timedetector/TimeDetectorShellCommand.java +++ b/services/core/java/com/android/server/timedetector/TimeDetectorShellCommand.java @@ -17,14 +17,26 @@ package com.android.server.timedetector; import static android.app.timedetector.TimeDetector.SHELL_COMMAND_IS_AUTO_DETECTION_ENABLED; import static android.app.timedetector.TimeDetector.SHELL_COMMAND_SERVICE_NAME; +import static android.app.timedetector.TimeDetector.SHELL_COMMAND_SUGGEST_EXTERNAL_TIME; +import static android.app.timedetector.TimeDetector.SHELL_COMMAND_SUGGEST_GNSS_TIME; +import static android.app.timedetector.TimeDetector.SHELL_COMMAND_SUGGEST_MANUAL_TIME; +import static android.app.timedetector.TimeDetector.SHELL_COMMAND_SUGGEST_NETWORK_TIME; +import static android.app.timedetector.TimeDetector.SHELL_COMMAND_SUGGEST_TELEPHONY_TIME; import static android.provider.DeviceConfig.NAMESPACE_SYSTEM_TIME; import static com.android.server.timedetector.ServerFlags.KEY_TIME_DETECTOR_LOWER_BOUND_MILLIS_OVERRIDE; import static com.android.server.timedetector.ServerFlags.KEY_TIME_DETECTOR_ORIGIN_PRIORITIES_OVERRIDE; +import android.app.time.ExternalTimeSuggestion; +import android.app.timedetector.GnssTimeSuggestion; +import android.app.timedetector.ManualTimeSuggestion; +import android.app.timedetector.NetworkTimeSuggestion; +import android.app.timedetector.TelephonyTimeSuggestion; import android.os.ShellCommand; import java.io.PrintWriter; +import java.util.function.Consumer; +import java.util.function.Supplier; /** Implements the shell command interface for {@link TimeDetectorService}. */ class TimeDetectorShellCommand extends ShellCommand { @@ -44,6 +56,16 @@ class TimeDetectorShellCommand extends ShellCommand { switch (cmd) { case SHELL_COMMAND_IS_AUTO_DETECTION_ENABLED: return runIsAutoDetectionEnabled(); + case SHELL_COMMAND_SUGGEST_MANUAL_TIME: + return runSuggestManualTime(); + case SHELL_COMMAND_SUGGEST_TELEPHONY_TIME: + return runSuggestTelephonyTime(); + case SHELL_COMMAND_SUGGEST_NETWORK_TIME: + return runSuggestNetworkTime(); + case SHELL_COMMAND_SUGGEST_GNSS_TIME: + return runSuggestGnssTime(); + case SHELL_COMMAND_SUGGEST_EXTERNAL_TIME: + return runSuggestExternalTime(); default: { return handleDefaultCommands(cmd); } @@ -59,6 +81,53 @@ class TimeDetectorShellCommand extends ShellCommand { return 0; } + private int runSuggestManualTime() { + return runSuggestTime( + () -> ManualTimeSuggestion.parseCommandLineArg(this), + mInterface::suggestManualTime); + } + + private int runSuggestTelephonyTime() { + return runSuggestTime( + () -> TelephonyTimeSuggestion.parseCommandLineArg(this), + mInterface::suggestTelephonyTime); + } + + private int runSuggestNetworkTime() { + return runSuggestTime( + () -> NetworkTimeSuggestion.parseCommandLineArg(this), + mInterface::suggestNetworkTime); + } + + private int runSuggestGnssTime() { + return runSuggestTime( + () -> GnssTimeSuggestion.parseCommandLineArg(this), + mInterface::suggestGnssTime); + } + + private int runSuggestExternalTime() { + return runSuggestTime( + () -> ExternalTimeSuggestion.parseCommandLineArg(this), + mInterface::suggestExternalTime); + } + + private <T> int runSuggestTime(Supplier<T> suggestionParser, Consumer<T> invoker) { + final PrintWriter pw = getOutPrintWriter(); + try { + T suggestion = suggestionParser.get(); + if (suggestion == null) { + pw.println("Error: suggestion not specified"); + return 1; + } + invoker.accept(suggestion); + pw.println("Suggestion " + suggestion + " injected."); + return 0; + } catch (RuntimeException e) { + pw.println(e); + return 1; + } + } + @Override public void onHelp() { final PrintWriter pw = getOutPrintWriter(); @@ -68,6 +137,22 @@ class TimeDetectorShellCommand extends ShellCommand { pw.printf(" %s\n", SHELL_COMMAND_IS_AUTO_DETECTION_ENABLED); pw.printf(" Prints true/false according to the automatic time detection setting.\n"); pw.println(); + pw.printf(" %s <manual suggestion opts>\n", SHELL_COMMAND_SUGGEST_MANUAL_TIME); + pw.printf(" %s <telephony suggestion opts>\n", SHELL_COMMAND_SUGGEST_TELEPHONY_TIME); + pw.printf(" %s <network suggestion opts>\n", SHELL_COMMAND_SUGGEST_NETWORK_TIME); + pw.printf(" %s <gnss suggestion opts>\n", SHELL_COMMAND_SUGGEST_GNSS_TIME); + pw.printf(" %s <external suggestion opts>\n", SHELL_COMMAND_SUGGEST_EXTERNAL_TIME); + pw.println(); + ManualTimeSuggestion.printCommandLineOpts(pw); + pw.println(); + TelephonyTimeSuggestion.printCommandLineOpts(pw); + pw.println(); + NetworkTimeSuggestion.printCommandLineOpts(pw); + pw.println(); + GnssTimeSuggestion.printCommandLineOpts(pw); + pw.println(); + ExternalTimeSuggestion.printCommandLineOpts(pw); + pw.println(); pw.printf("This service is also affected by the following device_config flags in the" + " %s namespace:\n", NAMESPACE_SYSTEM_TIME); pw.printf(" %s\n", KEY_TIME_DETECTOR_LOWER_BOUND_MILLIS_OVERRIDE); diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java index ae4d46c387b9..33ab1047c763 100644 --- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java +++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java @@ -85,6 +85,9 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { */ private static final int KEEP_SUGGESTION_HISTORY_SIZE = 10; + /** The value in Unix epoch milliseconds of the Y2038 issue. */ + private static final long Y2038_LIMIT_IN_MILLIS = 1000L * Integer.MAX_VALUE; + /** * A log that records the decisions / decision metadata that affected the device's system clock * time. This is logged in bug reports to assist with debugging issues with detection. @@ -185,6 +188,12 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { /** Release the wake lock acquired by a call to {@link #acquireWakeLock()}. */ void releaseWakeLock(); + + /** + * Returns {@code true} if the device may be at risk of time_t overflow (because bionic + * defines time_t as a 32-bit signed integer for 32-bit processes). + */ + boolean deviceHasY2038Issue(); } static TimeDetectorStrategy create( @@ -333,6 +342,7 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { .mapToObj(TimeDetectorStrategy::originToString) .collect(joining(",", "[", "]")); ipw.println("mEnvironment.autoOriginPriorities()=" + priorities); + ipw.println("mEnvironment.deviceHasY2038Issue()=" + mEnvironment.deviceHasY2038Issue()); ipw.println("Time change log:"); ipw.increaseIndent(); // level 2 @@ -413,6 +423,16 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { + ", suggestion=" + suggestion); return false; } + + if (newUnixEpochTime.getValue() > Y2038_LIMIT_IN_MILLIS + && mEnvironment.deviceHasY2038Issue()) { + // This check won't prevent a device's system clock exceeding Integer.MAX_VALUE Unix + // seconds through the normal passage of time, but it will stop it jumping above 2038 + // because of a "bad" suggestion. b/204193177 + Slog.w(LOG_TAG, "Suggested value is above max time supported by this device." + + " suggestion=" + suggestion); + return false; + } return true; } diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp b/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp index 7e4f0e72b62d..2617f4d09ee7 100644 --- a/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp +++ b/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp @@ -38,5 +38,4 @@ android_test_helper_app { "androidx.test.rules", "truth-prebuilt", ], - platform_apis: true, } diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java index a227cd3c6f5c..035249e32d74 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java @@ -70,6 +70,7 @@ import com.google.common.collect.ImmutableMap; import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -516,6 +517,7 @@ public class RecoverableKeyStoreManagerTest { } } + @Ignore("Causing breakages so ignoring to resolve, b/231667368") @Test public void initRecoveryService_alwaysUpdatesCertsWhenTestRootCertIsUsed() throws Exception { int uid = Binder.getCallingUid(); @@ -539,6 +541,7 @@ public class RecoverableKeyStoreManagerTest { testRootCertAlias)).isEqualTo(TestData.getInsecureCertPathForEndpoint2()); } + @Ignore("Causing breakages so ignoring to resolve, b/231667368") @Test public void initRecoveryService_updatesCertsIndependentlyForDifferentRoots() throws Exception { int uid = Binder.getCallingUid(); diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java index 2d9903f9cf60..2248ddb9e69a 100644 --- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java +++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java @@ -1131,6 +1131,49 @@ public class TimeDetectorStrategyImplTest { .verifySystemClockWasSetAndResetCallTracking(ARBITRARY_TEST_TIME.toEpochMilli()); } + @Test + public void manualY2038SuggestionsAreRejectedOnAffectedDevices() { + mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO) + .pokeAutoTimeDetectionEnabled(false) + .pokeAutoOriginPriorities(ORIGIN_TELEPHONY) + .pokeDeviceHasY2038Issues(true); + + Instant y2038IssueTime = Instant.ofEpochMilli((1L + Integer.MAX_VALUE) * 1000L); + ManualTimeSuggestion timeSuggestion = mScript.generateManualTimeSuggestion(y2038IssueTime); + mScript.simulateManualTimeSuggestion(timeSuggestion, false /* expectedResult */) + .verifySystemClockWasNotSetAndResetCallTracking(); + } + + @Test + public void telephonyY2038SuggestionsAreRejectedOnAffectedDevices() { + mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO) + .pokeAutoTimeDetectionEnabled(true) + .pokeAutoOriginPriorities(ORIGIN_TELEPHONY) + .pokeDeviceHasY2038Issues(true); + + final int slotIndex = 0; + Instant y2038IssueTime = Instant.ofEpochMilli((1L + Integer.MAX_VALUE) * 1000L); + TelephonyTimeSuggestion timeSuggestion = + mScript.generateTelephonyTimeSuggestion(slotIndex, y2038IssueTime); + mScript.simulateTelephonyTimeSuggestion(timeSuggestion) + .verifySystemClockWasNotSetAndResetCallTracking(); + } + + @Test + public void telephonyY2038SuggestionsAreNotRejectedOnUnaffectedDevices() { + mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO) + .pokeAutoTimeDetectionEnabled(true) + .pokeAutoOriginPriorities(ORIGIN_TELEPHONY) + .pokeDeviceHasY2038Issues(false); + + final int slotIndex = 0; + Instant y2038IssueTime = Instant.ofEpochMilli((1L + Integer.MAX_VALUE) * 1000L); + TelephonyTimeSuggestion timeSuggestion = + mScript.generateTelephonyTimeSuggestion(slotIndex, y2038IssueTime); + mScript.simulateTelephonyTimeSuggestion(timeSuggestion) + .verifySystemClockWasSetAndResetCallTracking(y2038IssueTime.toEpochMilli()); + } + /** * A fake implementation of {@link TimeDetectorStrategyImpl.Environment}. Besides tracking * changes and behaving like the real thing should, it also asserts preconditions. @@ -1143,6 +1186,7 @@ public class TimeDetectorStrategyImplTest { private int mSystemClockUpdateThresholdMillis = 2000; private int[] mAutoOriginPriorities = PROVIDERS_PRIORITY; private ConfigurationChangeListener mConfigChangeListener; + private boolean mDeviceHas2038Issues = false; // Tracking operations. private boolean mSystemClockWasSet; @@ -1208,6 +1252,15 @@ public class TimeDetectorStrategyImplTest { mWakeLockAcquired = false; } + public void setDeviceHas2038Issues(boolean hasIssues) { + mDeviceHas2038Issues = hasIssues; + } + + @Override + public boolean deviceHasY2038Issue() { + return mDeviceHas2038Issues; + } + // Methods below are for managing the fake's behavior. void pokeSystemClockUpdateThreshold(int thresholdMillis) { @@ -1304,6 +1357,11 @@ public class TimeDetectorStrategyImplTest { return this; } + Script pokeDeviceHasY2038Issues(boolean hasIssues) { + mFakeEnvironment.setDeviceHas2038Issues(hasIssues); + return this; + } + long peekElapsedRealtimeMillis() { return mFakeEnvironment.peekElapsedRealtimeMillis(); } diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java index 6122b080c500..8a8cdb0c5f3b 100644 --- a/telecomm/java/android/telecom/TelecomManager.java +++ b/telecomm/java/android/telecom/TelecomManager.java @@ -20,6 +20,7 @@ import android.Manifest; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; import android.annotation.SuppressAutoDoc; import android.annotation.SuppressLint; @@ -31,6 +32,7 @@ import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; import android.net.Uri; import android.os.Build; import android.os.Bundle; @@ -70,6 +72,7 @@ import java.util.concurrent.Executor; */ @SuppressAutoDoc @SystemService(Context.TELECOM_SERVICE) +@RequiresFeature(PackageManager.FEATURE_TELECOM) public class TelecomManager { /** diff --git a/telephony/java/android/telephony/AnomalyReporter.java b/telephony/java/android/telephony/AnomalyReporter.java index f47cf3384791..e7d95e4f53b3 100644 --- a/telephony/java/android/telephony/AnomalyReporter.java +++ b/telephony/java/android/telephony/AnomalyReporter.java @@ -16,6 +16,8 @@ package android.telephony; +import static android.telephony.TelephonyManager.UNKNOWN_CARRIER_ID; + import static com.android.internal.telephony.TelephonyStatsLog.TELEPHONY_ANOMALY_DETECTED; import android.annotation.NonNull; @@ -73,6 +75,7 @@ public final class AnomalyReporter { * * This method sends the {@link TelephonyManager#ACTION_ANOMALY_REPORTED} broadcast, which is * system protected. Invoking this method unless you are the system will result in an error. + * Carrier Id will be set as UNKNOWN_CARRIER_ID. * * @param eventId a fixed event ID that will be sent for each instance of the same event. This * ID should be generated randomly. @@ -81,6 +84,23 @@ public final class AnomalyReporter { * static and must not contain any sensitive information (especially PII). */ public static void reportAnomaly(@NonNull UUID eventId, String description) { + reportAnomaly(eventId, description, UNKNOWN_CARRIER_ID); + } + + /** + * If enabled, build and send an intent to a Debug Service for logging. + * + * This method sends the {@link TelephonyManager#ACTION_ANOMALY_REPORTED} broadcast, which is + * system protected. Invoking this method unless you are the system will result in an error. + * + * @param eventId a fixed event ID that will be sent for each instance of the same event. This + * ID should be generated randomly. + * @param description an optional description, that if included will be used as the subject for + * identification and discussion of this event. This description should ideally be + * static and must not contain any sensitive information (especially PII). + * @param carrierId the carrier of the id associated with this event. + */ + public static void reportAnomaly(@NonNull UUID eventId, String description, int carrierId) { if (sContext == null) { Rlog.w(TAG, "AnomalyReporter not yet initialized, dropping event=" + eventId); return; @@ -88,7 +108,7 @@ public final class AnomalyReporter { TelephonyStatsLog.write( TELEPHONY_ANOMALY_DETECTED, - 0, // TODO: carrier id needs to be populated + carrierId, eventId.getLeastSignificantBits(), eventId.getMostSignificantBits()); diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 0d0142c330ce..8956b4652f66 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -20,6 +20,7 @@ import android.Manifest; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; import android.annotation.SuppressAutoDoc; import android.annotation.SuppressLint; @@ -28,6 +29,7 @@ import android.annotation.SystemService; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; +import android.content.pm.PackageManager; import android.net.NetworkCapabilities; import android.net.ipsec.ike.SaProposal; import android.os.Build; @@ -55,6 +57,7 @@ import java.util.concurrent.TimeUnit; * Provides access to telephony configuration values that are carrier-specific. */ @SystemService(Context.CARRIER_CONFIG_SERVICE) +@RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public class CarrierConfigManager { private final static String TAG = "CarrierConfigManager"; diff --git a/telephony/java/android/telephony/DataFailCause.java b/telephony/java/android/telephony/DataFailCause.java index fa6de1ad2864..ac1f376cf6b5 100644 --- a/telephony/java/android/telephony/DataFailCause.java +++ b/telephony/java/android/telephony/DataFailCause.java @@ -1673,4 +1673,9 @@ public final class DataFailCause { return UNKNOWN; } } + + /** @hide */ + public static boolean isFailCauseExisting(@DataFailureCause int failCause) { + return sFailCauseMap.containsKey(failCause); + } } diff --git a/telephony/java/android/telephony/ImsManager.java b/telephony/java/android/telephony/ImsManager.java index 6b9871c3f5d7..b0ff9499eac4 100644 --- a/telephony/java/android/telephony/ImsManager.java +++ b/telephony/java/android/telephony/ImsManager.java @@ -17,11 +17,13 @@ package android.telephony.ims; import android.annotation.NonNull; +import android.annotation.RequiresFeature; import android.annotation.SdkConstant; import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; import android.content.Context; +import android.content.pm.PackageManager; import android.telephony.BinderCacheManager; import android.telephony.SubscriptionManager; import android.telephony.TelephonyFrameworkInitializer; @@ -33,6 +35,7 @@ import com.android.internal.telephony.ITelephony; * Provides access to information about Telephony IMS services on the device. */ @SystemService(Context.TELEPHONY_IMS_SERVICE) +@RequiresFeature(PackageManager.FEATURE_TELEPHONY_IMS) public class ImsManager { /** diff --git a/telephony/java/android/telephony/PhysicalChannelConfig.java b/telephony/java/android/telephony/PhysicalChannelConfig.java index d91134e33ef3..d978f5701eca 100644 --- a/telephony/java/android/telephony/PhysicalChannelConfig.java +++ b/telephony/java/android/telephony/PhysicalChannelConfig.java @@ -23,16 +23,12 @@ import android.os.Parcel; import android.os.Parcelable; import android.telephony.Annotation.NetworkType; -import com.android.telephony.Rlog; - import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Arrays; import java.util.Objects; public final class PhysicalChannelConfig implements Parcelable { - static final String TAG = "PhysicalChannelConfig"; - // TODO(b/72993578) consolidate these enums in a central location. /** @hide */ @Retention(RetentionPolicy.SOURCE) @@ -571,21 +567,19 @@ public final class PhysicalChannelConfig implements Parcelable { public @NonNull Builder setNetworkType(@NetworkType int networkType) { if (!TelephonyManager.isNetworkTypeValid(networkType)) { - Rlog.e(TAG, "Builder.setNetworkType: Network type " + networkType + " is invalid."); - } else { - mNetworkType = networkType; + throw new IllegalArgumentException("Network type " + networkType + " is invalid."); } + mNetworkType = networkType; return this; } public @NonNull Builder setFrequencyRange(int frequencyRange) { if (!ServiceState.isFrequencyRangeValid(frequencyRange) && frequencyRange != ServiceState.FREQUENCY_RANGE_UNKNOWN) { - Rlog.e(TAG, "Builder.setFrequencyRange: Frequency range " + frequencyRange + throw new IllegalArgumentException("Frequency range " + frequencyRange + " is invalid."); - } else { - mFrequencyRange = frequencyRange; } + mFrequencyRange = frequencyRange; return this; } @@ -601,21 +595,19 @@ public final class PhysicalChannelConfig implements Parcelable { public @NonNull Builder setCellBandwidthDownlinkKhz(int cellBandwidthDownlinkKhz) { if (cellBandwidthDownlinkKhz < CELL_BANDWIDTH_UNKNOWN) { - Rlog.e(TAG, "Builder.setCellBandwidthDownlinkKhz: Cell downlink bandwidth(kHz) " + throw new IllegalArgumentException("Cell downlink bandwidth(kHz) " + cellBandwidthDownlinkKhz + " is invalid."); - } else { - mCellBandwidthDownlinkKhz = cellBandwidthDownlinkKhz; } + mCellBandwidthDownlinkKhz = cellBandwidthDownlinkKhz; return this; } public @NonNull Builder setCellBandwidthUplinkKhz(int cellBandwidthUplinkKhz) { if (cellBandwidthUplinkKhz < CELL_BANDWIDTH_UNKNOWN) { - Rlog.e(TAG, "Builder.setCellBandwidthUplinkKhz: Cell uplink bandwidth(kHz) " + throw new IllegalArgumentException("Cell uplink bandwidth(kHz) " + cellBandwidthUplinkKhz + " is invalid."); - } else { - mCellBandwidthUplinkKhz = cellBandwidthUplinkKhz; } + mCellBandwidthUplinkKhz = cellBandwidthUplinkKhz; return this; } @@ -632,20 +624,18 @@ public final class PhysicalChannelConfig implements Parcelable { public @NonNull Builder setPhysicalCellId(int physicalCellId) { if (physicalCellId > PHYSICAL_CELL_ID_MAXIMUM_VALUE) { - Rlog.e(TAG, "Builder.setPhysicalCellId: Physical cell ID " + physicalCellId + throw new IllegalArgumentException("Physical cell ID " + physicalCellId + " is over limit."); - } else { - mPhysicalCellId = physicalCellId; } + mPhysicalCellId = physicalCellId; return this; } public @NonNull Builder setBand(int band) { if (band <= BAND_UNKNOWN) { - Rlog.e(TAG, "Builder.setBand: Band " + band + " is invalid."); - } else { - mBand = band; + throw new IllegalArgumentException("Band " + band + " is invalid."); } + mBand = band; return this; } } diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java index 5171cf9dcea7..7df06b09c6bb 100644 --- a/telephony/java/android/telephony/SmsManager.java +++ b/telephony/java/android/telephony/SmsManager.java @@ -22,6 +22,7 @@ import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; import android.annotation.SuppressAutoDoc; import android.annotation.SystemApi; @@ -32,6 +33,7 @@ import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledAfter; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; +import android.content.pm.PackageManager; import android.database.CursorWindow; import android.net.Uri; import android.os.Build; @@ -75,6 +77,7 @@ import java.util.concurrent.Executor; * * @see SubscriptionManager#getActiveSubscriptionInfoList() */ +@RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING) public final class SmsManager { private static final String TAG = "SmsManager"; @@ -2633,6 +2636,19 @@ public final class SmsManager { * sending the message. * @param sentIntent if not NULL this <code>PendingIntent</code> is * broadcast when the message is successfully sent, or failed + * The result code will be <code>Activity.RESULT_OK</code> for success + * or one of these errors:<br> + * <code>MMS_ERROR_UNSPECIFIED</code><br> + * <code>MMS_ERROR_INVALID_APN</code><br> + * <code>MMS_ERROR_UNABLE_CONNECT_MMS</code><br> + * <code>MMS_ERROR_HTTP_FAILURE</code><br> + * <code>MMS_ERROR_IO_ERROR</code><br> + * <code>MMS_ERROR_RETRY</code><br> + * <code>MMS_ERROR_CONFIGURATION_ERROR</code><br> + * <code>MMS_ERROR_NO_DATA_NETWORK</code><br> + * <code>MMS_ERROR_INVALID_SUBSCRIPTION_ID</code><br> + * <code>MMS_ERROR_INACTIVE_SUBSCRIPTION</code><br> + * <code>MMS_ERROR_DATA_DISABLED</code><br> * @throws IllegalArgumentException if contentUri is empty */ public void sendMultimediaMessage(Context context, Uri contentUri, String locationUrl, @@ -2661,6 +2677,19 @@ public final class SmsManager { * sending the message. * @param sentIntent if not NULL this <code>PendingIntent</code> is * broadcast when the message is successfully sent, or failed + * The result code will be <code>Activity.RESULT_OK</code> for success + * or one of these errors:<br> + * <code>MMS_ERROR_UNSPECIFIED</code><br> + * <code>MMS_ERROR_INVALID_APN</code><br> + * <code>MMS_ERROR_UNABLE_CONNECT_MMS</code><br> + * <code>MMS_ERROR_HTTP_FAILURE</code><br> + * <code>MMS_ERROR_IO_ERROR</code><br> + * <code>MMS_ERROR_RETRY</code><br> + * <code>MMS_ERROR_CONFIGURATION_ERROR</code><br> + * <code>MMS_ERROR_NO_DATA_NETWORK</code><br> + * <code>MMS_ERROR_INVALID_SUBSCRIPTION_ID</code><br> + * <code>MMS_ERROR_INACTIVE_SUBSCRIPTION</code><br> + * <code>MMS_ERROR_DATA_DISABLED</code><br> * @param messageId an id that uniquely identifies the message requested to be sent. * Used for logging and diagnostics purposes. The id may be 0. * @throws IllegalArgumentException if contentUri is empty @@ -2707,6 +2736,19 @@ public final class SmsManager { * downloading the message. * @param downloadedIntent if not NULL this <code>PendingIntent</code> is * broadcast when the message is downloaded, or the download is failed + * The result code will be <code>Activity.RESULT_OK</code> for success + * or one of these errors:<br> + * <code>MMS_ERROR_UNSPECIFIED</code><br> + * <code>MMS_ERROR_INVALID_APN</code><br> + * <code>MMS_ERROR_UNABLE_CONNECT_MMS</code><br> + * <code>MMS_ERROR_HTTP_FAILURE</code><br> + * <code>MMS_ERROR_IO_ERROR</code><br> + * <code>MMS_ERROR_RETRY</code><br> + * <code>MMS_ERROR_CONFIGURATION_ERROR</code><br> + * <code>MMS_ERROR_NO_DATA_NETWORK</code><br> + * <code>MMS_ERROR_INVALID_SUBSCRIPTION_ID</code><br> + * <code>MMS_ERROR_INACTIVE_SUBSCRIPTION</code><br> + * <code>MMS_ERROR_DATA_DISABLED</code><br> * @throws IllegalArgumentException if locationUrl or contentUri is empty */ public void downloadMultimediaMessage(Context context, String locationUrl, Uri contentUri, @@ -2737,6 +2779,19 @@ public final class SmsManager { * downloading the message. * @param downloadedIntent if not NULL this <code>PendingIntent</code> is * broadcast when the message is downloaded, or the download is failed + * The result code will be <code>Activity.RESULT_OK</code> for success + * or one of these errors:<br> + * <code>MMS_ERROR_UNSPECIFIED</code><br> + * <code>MMS_ERROR_INVALID_APN</code><br> + * <code>MMS_ERROR_UNABLE_CONNECT_MMS</code><br> + * <code>MMS_ERROR_HTTP_FAILURE</code><br> + * <code>MMS_ERROR_IO_ERROR</code><br> + * <code>MMS_ERROR_RETRY</code><br> + * <code>MMS_ERROR_CONFIGURATION_ERROR</code><br> + * <code>MMS_ERROR_NO_DATA_NETWORK</code><br> + * <code>MMS_ERROR_INVALID_SUBSCRIPTION_ID</code><br> + * <code>MMS_ERROR_INACTIVE_SUBSCRIPTION</code><br> + * <code>MMS_ERROR_DATA_DISABLED</code><br> * @param messageId an id that uniquely identifies the message requested to be downloaded. * Used for logging and diagnostics purposes. The id may be 0. * @throws IllegalArgumentException if locationUrl or contentUri is empty @@ -2768,15 +2823,62 @@ public final class SmsManager { } // MMS send/download failure result codes + + /** + * Unspecific MMS error occurred during send/download. + */ public static final int MMS_ERROR_UNSPECIFIED = 1; + + /** + * ApnException occurred during MMS network setup. + */ public static final int MMS_ERROR_INVALID_APN = 2; + + /** + * An error occurred during the MMS connection setup. + */ public static final int MMS_ERROR_UNABLE_CONNECT_MMS = 3; + + /** + * An error occurred during the HTTP client setup. + */ public static final int MMS_ERROR_HTTP_FAILURE = 4; + + /** + * An I/O error occurred reading the PDU. + */ public static final int MMS_ERROR_IO_ERROR = 5; + + /** + * An error occurred while retrying sending/downloading the MMS. + */ public static final int MMS_ERROR_RETRY = 6; + + /** + * The carrier-dependent configuration values could not be loaded. + */ public static final int MMS_ERROR_CONFIGURATION_ERROR = 7; + + /** + * There is no data network. + */ public static final int MMS_ERROR_NO_DATA_NETWORK = 8; + /** + * The subscription id for the send/download is invalid. + */ + public static final int MMS_ERROR_INVALID_SUBSCRIPTION_ID = 9; + + /** + * The subscription id for the send/download is inactive. + */ + public static final int MMS_ERROR_INACTIVE_SUBSCRIPTION = 10; + + /** + * Data is disabled for the MMS APN. + */ + public static final int MMS_ERROR_DATA_DISABLED = 11; + /** Intent extra name for MMS sending result data in byte array type */ public static final String EXTRA_MMS_DATA = "android.telephony.extra.MMS_DATA"; /** Intent extra name for HTTP status code for MMS HTTP failure in integer type */ diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 974392ea31eb..d2858eca8171 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -26,6 +26,7 @@ import android.annotation.DurationMillisLong; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; @@ -92,6 +93,7 @@ import java.util.stream.Collectors; * and provides information about the current Telephony Subscriptions. */ @SystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE) +@RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public class SubscriptionManager { private static final String LOG_TAG = "SubscriptionManager"; private static final boolean DBG = false; diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 87c337da8ccb..bbd3c46c0d68 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -49,6 +49,7 @@ import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; import android.database.Cursor; import android.net.ConnectivityManager; import android.net.Uri; @@ -174,6 +175,7 @@ import java.util.stream.IntStream; * that do not implement this feature, the behavior is not reliable. */ @SystemService(Context.TELEPHONY_SERVICE) +@RequiresFeature(PackageManager.FEATURE_TELEPHONY) public class TelephonyManager { private static final String TAG = "TelephonyManager"; @@ -2055,6 +2057,7 @@ public class TelephonyManager { */ @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236). @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_GSM) public String getImei() { return getImei(getSlotIndex()); } @@ -2096,6 +2099,7 @@ public class TelephonyManager { */ @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236). @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_GSM) public String getImei(int slotIndex) { ITelephony telephony = getITelephony(); if (telephony == null) return null; @@ -2113,6 +2117,7 @@ public class TelephonyManager { * Returns the Type Allocation Code from the IMEI. Return null if Type Allocation Code is not * available. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_GSM) @Nullable public String getTypeAllocationCode() { return getTypeAllocationCode(getSlotIndex()); @@ -2124,6 +2129,7 @@ public class TelephonyManager { * * @param slotIndex of which Type Allocation Code is returned */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_GSM) @Nullable public String getTypeAllocationCode(int slotIndex) { ITelephony telephony = getITelephony(); @@ -2170,6 +2176,7 @@ public class TelephonyManager { */ @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236). @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA) public String getMeid() { return getMeid(getSlotIndex()); } @@ -2208,6 +2215,7 @@ public class TelephonyManager { */ @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236). @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA) public String getMeid(int slotIndex) { ITelephony telephony = getITelephony(); if (telephony == null) return null; @@ -2231,6 +2239,7 @@ public class TelephonyManager { * Returns the Manufacturer Code from the MEID. Return null if Manufacturer Code is not * available. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA) @Nullable public String getManufacturerCode() { return getManufacturerCode(getSlotIndex()); @@ -2242,6 +2251,7 @@ public class TelephonyManager { * * @param slotIndex of which Type Allocation Code is returned */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA) @Nullable public String getManufacturerCode(int slotIndex) { ITelephony telephony = getITelephony(); @@ -2287,6 +2297,7 @@ public class TelephonyManager { */ @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236). @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public String getNai() { return getNaiBySubscriberId(getSubId()); } @@ -2620,6 +2631,7 @@ public class TelephonyManager { * unreliable on CDMA networks (use {@link #getPhoneType()} to determine if * on a CDMA network). */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) public String getNetworkOperatorName() { return getNetworkOperatorName(getSubId()); } @@ -2647,6 +2659,7 @@ public class TelephonyManager { * unreliable on CDMA networks (use {@link #getPhoneType()} to determine if * on a CDMA network). */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) public String getNetworkOperator() { return getNetworkOperatorForPhone(getPhoneId()); } @@ -2695,6 +2708,7 @@ public class TelephonyManager { * @see #createForSubscriptionId(int) * @see #createForPhoneAccountHandle(PhoneAccountHandle) */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA) public String getNetworkSpecifier() { return String.valueOf(getSubId()); } @@ -2717,6 +2731,7 @@ public class TelephonyManager { @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @WorkerThread @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public PersistableBundle getCarrierConfig() { CarrierConfigManager carrierConfigManager = mContext .getSystemService(CarrierConfigManager.class); @@ -2729,6 +2744,7 @@ public class TelephonyManager { * <p> * Availability: Only when user registered to a network. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) public boolean isNetworkRoaming() { return isNetworkRoaming(getSubId()); } @@ -2758,6 +2774,7 @@ public class TelephonyManager { * @return the lowercase 2 character ISO-3166-1 alpha-2 country code, or empty string if not * available. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) public String getNetworkCountryIso() { return getNetworkCountryIso(getSlotIndex()); } @@ -2780,6 +2797,7 @@ public class TelephonyManager { * @throws IllegalArgumentException when the slotIndex is invalid. * */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) @NonNull public String getNetworkCountryIso(int slotIndex) { try { @@ -2997,6 +3015,7 @@ public class TelephonyManager { @RequiresPermission(anyOf = { android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.READ_BASIC_PHONE_STATE}) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA) public @NetworkType int getDataNetworkType() { return getDataNetworkType(getSubId(SubscriptionManager.getActiveDataSubscriptionId())); } @@ -3042,6 +3061,7 @@ public class TelephonyManager { @RequiresPermission(anyOf = { android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.READ_BASIC_PHONE_STATE}) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING) public @NetworkType int getVoiceNetworkType() { return getVoiceNetworkType(getSubId()); } @@ -3381,6 +3401,7 @@ public class TelephonyManager { /** * @return true if a ICC card is present */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public boolean hasIccCard() { return hasIccCard(getSlotIndex()); } @@ -3423,6 +3444,7 @@ public class TelephonyManager { * @see #SIM_STATE_CARD_IO_ERROR * @see #SIM_STATE_CARD_RESTRICTED */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public @SimState int getSimState() { int simState = getSimStateIncludingLoaded(); if (simState == SIM_STATE_LOADED) { @@ -3465,6 +3487,7 @@ public class TelephonyManager { * @hide */ @SystemApi + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public @SimState int getSimCardState() { int simState = getSimState(); return getSimCardStateFromSimState(simState); @@ -3510,6 +3533,7 @@ public class TelephonyManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public @SimState int getSimCardState(int physicalSlotIndex, int portIndex) { int simState = getSimState(getLogicalSlotIndex(physicalSlotIndex, portIndex)); return getSimCardStateFromSimState(simState); @@ -3566,6 +3590,7 @@ public class TelephonyManager { * @hide */ @SystemApi + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public @SimState int getSimApplicationState() { int simState = getSimStateIncludingLoaded(); return getSimApplicationStateFromSimState(simState); @@ -3618,6 +3643,7 @@ public class TelephonyManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public @SimState int getSimApplicationState(int physicalSlotIndex, int portIndex) { int simState = SubscriptionManager.getSimStateForSlotIndex(getLogicalSlotIndex(physicalSlotIndex, @@ -3659,6 +3685,7 @@ public class TelephonyManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public boolean isApplicationOnUicc(@UiccAppType int appType) { try { ITelephony service = getITelephony(); @@ -3687,6 +3714,7 @@ public class TelephonyManager { * @see #SIM_STATE_CARD_IO_ERROR * @see #SIM_STATE_CARD_RESTRICTED */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public @SimState int getSimState(int slotIndex) { int simState = SubscriptionManager.getSimStateForSlotIndex(slotIndex); if (simState == SIM_STATE_LOADED) { @@ -3703,6 +3731,7 @@ public class TelephonyManager { * * @see #getSimState */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public String getSimOperator() { return getSimOperatorNumeric(); } @@ -3787,6 +3816,7 @@ public class TelephonyManager { * * @see #getSimState */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public String getSimOperatorName() { return getSimOperatorNameForPhone(getPhoneId()); } @@ -3824,6 +3854,7 @@ public class TelephonyManager { * @return the lowercase 2 character ISO-3166-1 alpha-2 country code, or empty string is not * available. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public String getSimCountryIso() { return getSimCountryIsoForPhone(getPhoneId()); } @@ -3882,6 +3913,7 @@ public class TelephonyManager { */ @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236). @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public String getSimSerialNumber() { return getSimSerialNumber(getSubId()); } @@ -3949,6 +3981,7 @@ public class TelephonyManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) public boolean isLteCdmaEvdoGsmWcdmaEnabled() { return getLteOnCdmaMode(getSubId()) == PhoneConstants.LTE_ON_CDMA_TRUE; } @@ -3992,6 +4025,7 @@ public class TelephonyManager { * * @return card ID of the default eUICC card, if loaded. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_EUICC) public int getCardIdForDefaultEuicc() { try { ITelephony telephony = getITelephony(); @@ -4025,6 +4059,7 @@ public class TelephonyManager { * the caller does not have adequate permissions for that card. */ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) @NonNull public List<UiccCardInfo> getUiccCardsInfo() { try { @@ -4050,6 +4085,7 @@ public class TelephonyManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public UiccSlotInfo[] getUiccSlotsInfo() { try { ITelephony telephony = getITelephony(); @@ -4192,6 +4228,7 @@ public class TelephonyManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public void setSimSlotMapping(@NonNull Collection<UiccSlotMapping> slotMapping) { try { ITelephony telephony = getITelephony(); @@ -4255,6 +4292,7 @@ public class TelephonyManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) @NonNull public Collection<UiccSlotMapping> getSimSlotMapping() { List<UiccSlotMapping> slotMap = new ArrayList<>(); @@ -4310,6 +4348,7 @@ public class TelephonyManager { */ @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236). @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public String getSubscriberId() { return getSubscriberId(getSubId()); } @@ -4361,6 +4400,7 @@ public class TelephonyManager { * @hide */ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) @SystemApi @Nullable public ImsiEncryptionInfo getCarrierInfoForImsiEncryption(@KeyType int keyType) { @@ -4405,6 +4445,7 @@ public class TelephonyManager { * @hide */ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) @SystemApi public void resetCarrierKeysForImsiEncryption() { try { @@ -4604,6 +4645,7 @@ public class TelephonyManager { * @param callback A callback called when the upload operation terminates, either in success * or in error. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING) public void uploadCallComposerPicture(@NonNull Path pictureToUpload, @NonNull String contentType, @CallbackExecutor @NonNull Executor executor, @@ -4710,6 +4752,7 @@ public class TelephonyManager { * @param callback A callback called when the upload operation terminates, either in success * or in error. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING) public void uploadCallComposerPicture(@NonNull InputStream pictureToUpload, @NonNull String contentType, @CallbackExecutor @NonNull Executor executor, @@ -4845,6 +4888,7 @@ public class TelephonyManager { */ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public String getGroupIdLevel1() { try { IPhoneSubInfo info = getSubscriberInfoService(); @@ -5100,6 +5144,7 @@ public class TelephonyManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public @NonNull String[] getMergedImsisFromGroup() { try { ITelephony telephony = getITelephony(); @@ -5179,6 +5224,7 @@ public class TelephonyManager { */ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING) public String getVoiceMailNumber() { return getVoiceMailNumber(getSubId()); } @@ -5214,6 +5260,7 @@ public class TelephonyManager { * @param alphaTag The alpha tag to display. * @param number The voicemail number. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING) public boolean setVoiceMailNumber(String alphaTag, String number) { return setVoiceMailNumber(getSubId(), alphaTag, number); } @@ -5253,6 +5300,7 @@ public class TelephonyManager { * be implemented instead. */ @SystemApi + @Deprecated @SuppressLint("RequiresPermission") public void setVisualVoicemailEnabled(PhoneAccountHandle phoneAccountHandle, boolean enabled){ } @@ -5267,6 +5315,7 @@ public class TelephonyManager { * be implemented instead. */ @SystemApi + @Deprecated @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) @SuppressLint("RequiresPermission") public boolean isVisualVoicemailEnabled(PhoneAccountHandle phoneAccountHandle){ @@ -5288,6 +5337,7 @@ public class TelephonyManager { */ @SystemApi @SuppressLint("RequiresPermission") + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING) @Nullable public Bundle getVisualVoicemailSettings(){ try { @@ -5317,6 +5367,7 @@ public class TelephonyManager { @Nullable @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING) public String getVisualVoicemailPackageName() { try { ITelephony telephony = getITelephony(); @@ -5343,6 +5394,7 @@ public class TelephonyManager { * @see TelecomManager#getDefaultDialerPackage() * @see CarrierConfigManager#KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING) public void setVisualVoicemailSmsFilterSettings(VisualVoicemailSmsFilterSettings settings) { if (settings == null) { disableVisualVoicemailSmsFilter(mSubId); @@ -5372,6 +5424,7 @@ public class TelephonyManager { * @see SmsManager#sendDataMessage(String, String, short, byte[], PendingIntent, PendingIntent) * @see SmsManager#sendTextMessage(String, String, String, PendingIntent, PendingIntent) */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING) public void sendVisualVoicemailSms(String number, int port, String text, PendingIntent sentIntent) { sendVisualVoicemailSmsForSubscriber(mSubId, number, port, text, sentIntent); @@ -5559,6 +5612,7 @@ public class TelephonyManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING) public void setVoiceActivationState(@SimActivationState int activationState) { setVoiceActivationState(getSubId(), activationState); } @@ -5606,6 +5660,7 @@ public class TelephonyManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA) public void setDataActivationState(@SimActivationState int activationState) { setDataActivationState(getSubId(), activationState); } @@ -5653,6 +5708,7 @@ public class TelephonyManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING) public @SimActivationState int getVoiceActivationState() { return getVoiceActivationState(getSubId()); } @@ -5702,6 +5758,7 @@ public class TelephonyManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA) public @SimActivationState int getDataActivationState() { return getDataActivationState(getSubId()); } @@ -5778,6 +5835,7 @@ public class TelephonyManager { */ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING) public String getVoiceMailAlphaTag() { return getVoiceMailAlphaTag(getSubId()); } @@ -5860,6 +5918,7 @@ public class TelephonyManager { @Nullable @SystemApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public String getIsimDomain() { try { IPhoneSubInfo info = getSubscriberInfoService(); @@ -5960,6 +6019,7 @@ public class TelephonyManager { * @return The call state of the subscription associated with this TelephonyManager instance. */ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING) public @CallState int getCallStateForSubscription() { return getCallState(getSubId()); } @@ -6058,6 +6118,7 @@ public class TelephonyManager { * @see #DATA_ACTIVITY_INOUT * @see #DATA_ACTIVITY_DORMANT */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA) public int getDataActivity() { try { ITelephony telephony = getITelephony(); @@ -6130,6 +6191,7 @@ public class TelephonyManager { * @see #DATA_DISCONNECTING * @see #DATA_HANDOVER_IN_PROGRESS */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA) public int getDataState() { try { ITelephony telephony = getITelephony(); @@ -6406,6 +6468,7 @@ public class TelephonyManager { * on any device with a telephony radio, even if the device is * data-only. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING) public boolean isVoiceCapable() { if (mContext == null) return true; return mContext.getResources().getBoolean( @@ -6421,6 +6484,7 @@ public class TelephonyManager { * Note: Voicemail waiting sms, cell broadcasting sms, and MMS are * disabled when device doesn't support sms. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING) public boolean isSmsCapable() { if (mContext == null) return true; return mContext.getResources().getBoolean( @@ -6470,6 +6534,7 @@ public class TelephonyManager { * information is unavailable. */ @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) public List<CellInfo> getAllCellInfo() { try { ITelephony telephony = getITelephony(); @@ -6564,6 +6629,7 @@ public class TelephonyManager { * @param callback a callback to receive CellInfo. */ @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) public void requestCellInfoUpdate( @NonNull @CallbackExecutor Executor executor, @NonNull CellInfoCallback callback) { try { @@ -6627,6 +6693,7 @@ public class TelephonyManager { @SystemApi @RequiresPermission(allOf = {android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.MODIFY_PHONE_STATE}) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) public void requestCellInfoUpdate(@NonNull WorkSource workSource, @NonNull @CallbackExecutor Executor executor, @NonNull CellInfoCallback callback) { try { @@ -6708,6 +6775,7 @@ public class TelephonyManager { /** * Returns the MMS user agent. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING) public String getMmsUserAgent() { try { ITelephony telephony = getITelephony(); @@ -6723,6 +6791,7 @@ public class TelephonyManager { /** * Returns the MMS user agent profile URL. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING) public String getMmsUAProfUrl() { try { ITelephony telephony = getITelephony(); @@ -6784,6 +6853,7 @@ public class TelephonyManager { * @deprecated instead use {@link #iccOpenLogicalChannelByPort(int, int, String, int)} */ @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) @SystemApi @Nullable @Deprecated @@ -6883,6 +6953,7 @@ public class TelephonyManager { * @param p2 P2 parameter (described in ISO 7816-4). * @return an IccOpenLogicalChannelResponse object. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public IccOpenLogicalChannelResponse iccOpenLogicalChannel(String AID, int p2) { return iccOpenLogicalChannel(getSubId(), AID, p2); } @@ -6951,6 +7022,7 @@ public class TelephonyManager { * @deprecated instead use {@link #iccCloseLogicalChannelByPort(int, int, int)} */ @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) @SystemApi @Deprecated public boolean iccCloseLogicalChannelBySlot(int slotIndex, int channel) { @@ -7020,6 +7092,7 @@ public class TelephonyManager { * iccOpenLogicalChannel. * @return true if the channel was closed successfully. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public boolean iccCloseLogicalChannel(int channel) { return iccCloseLogicalChannel(getSubId(), channel); } @@ -7082,6 +7155,7 @@ public class TelephonyManager { * {@link #iccTransmitApduLogicalChannelByPort(int, int, int, int, int, int, int, int, String)} */ @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) @SystemApi @Nullable @Deprecated @@ -7164,6 +7238,7 @@ public class TelephonyManager { * @return The APDU response from the ICC card with the status appended at * the end. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public String iccTransmitApduLogicalChannel(int channel, int cla, int instruction, int p1, int p2, int p3, String data) { return iccTransmitApduLogicalChannel(getSubId(), channel, cla, @@ -7232,6 +7307,7 @@ public class TelephonyManager { * {@link #iccTransmitApduBasicChannelByPort(int, int, int, int, int, int, int, String)} */ @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) @SystemApi @NonNull @Deprecated @@ -7309,6 +7385,7 @@ public class TelephonyManager { * @return The APDU response from the ICC card with the status appended at * the end. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public String iccTransmitApduBasicChannel(int cla, int instruction, int p1, int p2, int p3, String data) { return iccTransmitApduBasicChannel(getSubId(), cla, @@ -7364,6 +7441,7 @@ public class TelephonyManager { * @param filePath * @return The APDU response. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public byte[] iccExchangeSimIO(int fileID, int command, int p1, int p2, int p3, String filePath) { return iccExchangeSimIO(getSubId(), fileID, command, p1, p2, p3, filePath); @@ -7412,6 +7490,7 @@ public class TelephonyManager { * with the last 4 bytes being the status word. If the command fails, * returns an empty string. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public String sendEnvelopeWithStatus(String content) { return sendEnvelopeWithStatus(getSubId(), content); } @@ -7575,6 +7654,7 @@ public class TelephonyManager { */ @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) @SystemApi + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) public boolean resetRadioConfig() { try { ITelephony telephony = getITelephony(); @@ -7602,6 +7682,7 @@ public class TelephonyManager { */ @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) @SystemApi + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) public boolean rebootRadio() { try { ITelephony telephony = getITelephony(); @@ -7623,6 +7704,7 @@ public class TelephonyManager { * subscription ID is returned. Otherwise, the default subscription ID will be returned. * */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public int getSubscriptionId() { return getSubId(); } @@ -7733,6 +7815,7 @@ public class TelephonyManager { */ @SystemApi @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING) public void requestNumberVerification(@NonNull PhoneNumberRange range, long timeoutMillis, @NonNull @CallbackExecutor Executor executor, @NonNull NumberVerificationCallback callback) { @@ -7946,6 +8029,7 @@ public class TelephonyManager { @Nullable @SystemApi @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public String getIsimIst() { try { IPhoneSubInfo info = getSubscriberInfoService(); @@ -8030,6 +8114,7 @@ public class TelephonyManager { // TODO(b/73660190): This should probably require MODIFY_PHONE_STATE, not // READ_PRIVILEGED_PHONE_STATE. It certainly shouldn't reference the permission in Javadoc since // it's not public API. + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public String getIccAuthentication(int appType, int authType, String data) { return getIccAuthentication(getSubId(), appType, authType, data); } @@ -8083,6 +8168,7 @@ public class TelephonyManager { */ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public String[] getForbiddenPlmns() { return getForbiddenPlmns(getSubId(), APPTYPE_USIM); } @@ -8132,6 +8218,7 @@ public class TelephonyManager { */ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public int setForbiddenPlmns(@NonNull List<String> fplmns) { try { ITelephony telephony = getITelephony(); @@ -8158,6 +8245,7 @@ public class TelephonyManager { @SystemApi @WorkerThread @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_IMS) public void resetIms(int slotIndex) { try { ITelephony telephony = getITelephony(); @@ -8592,6 +8680,7 @@ public class TelephonyManager { */ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @SystemApi + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) public @NetworkTypeBitMask long getAllowedNetworkTypesBitmask() { try { ITelephony telephony = getITelephony(); @@ -8643,6 +8732,7 @@ public class TelephonyManager { */ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) public void setNetworkSelectionModeAutomatic() { try { ITelephony telephony = getITelephony(); @@ -8731,6 +8821,7 @@ public class TelephonyManager { android.Manifest.permission.MODIFY_PHONE_STATE, Manifest.permission.ACCESS_FINE_LOCATION }) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) public NetworkScan requestNetworkScan( NetworkScanRequest request, Executor executor, TelephonyScanManager.NetworkScanCallback callback) { @@ -8823,6 +8914,7 @@ public class TelephonyManager { */ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) public boolean setNetworkSelectionModeManual(String operatorNumeric, boolean persistSelection) { return setNetworkSelectionModeManual( new OperatorInfo( @@ -8852,6 +8944,7 @@ public class TelephonyManager { * @return {@code true} on success; {@code false} on any failure. */ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) public boolean setNetworkSelectionModeManual(@NonNull String operatorNumeric, boolean persistSelection, @AccessNetworkConstants.RadioAccessNetworkType int ran) { return setNetworkSelectionModeManual(new OperatorInfo("" /* operatorAlphaLong */, @@ -8907,6 +9000,7 @@ public class TelephonyManager { android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PRECISE_PHONE_STATE }) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) public @NetworkSelectionMode int getNetworkSelectionMode() { int mode = NETWORK_SELECTION_MODE_UNKNOWN; try { @@ -8932,6 +9026,7 @@ public class TelephonyManager { */ @SuppressAutoDoc // No support carrier privileges (b/72967236). @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) public @NonNull String getManualNetworkSelectionPlmn() { try { ITelephony telephony = getITelephony(); @@ -8961,6 +9056,7 @@ public class TelephonyManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING) public boolean isInEmergencySmsMode() { try { ITelephony telephony = getITelephony(); @@ -9271,6 +9367,7 @@ public class TelephonyManager { * * @return true on success; false on any failure. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) public boolean setPreferredNetworkTypeToGlobal() { return setPreferredNetworkTypeToGlobal(getSubId()); } @@ -9298,6 +9395,7 @@ public class TelephonyManager { */ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @SystemApi + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA) public boolean isTetheringApnRequired() { return isTetheringApnRequired(getSubId(SubscriptionManager.getActiveDataSubscriptionId())); } @@ -9347,6 +9445,7 @@ public class TelephonyManager { * * @return true if the app has carrier privileges. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public boolean hasCarrierPrivileges() { return hasCarrierPrivileges(getSubId()); } @@ -9393,6 +9492,7 @@ public class TelephonyManager { * @param brand The brand name to display/set. * @return true if the operation was executed correctly. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public boolean setOperatorBrandOverride(String brand) { return setOperatorBrandOverride(getSubId(), brand); } @@ -9495,6 +9595,7 @@ public class TelephonyManager { /** @hide */ @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA) public String getCdmaMdn() { return getCdmaMdn(getSubId()); } @@ -9502,6 +9603,7 @@ public class TelephonyManager { /** @hide */ @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA) public String getCdmaMdn(int subId) { try { ITelephony telephony = getITelephony(); @@ -9518,6 +9620,7 @@ public class TelephonyManager { /** @hide */ @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA) public String getCdmaMin() { return getCdmaMin(getSubId()); } @@ -9525,6 +9628,7 @@ public class TelephonyManager { /** @hide */ @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA) public String getCdmaMin(int subId) { try { ITelephony telephony = getITelephony(); @@ -9541,6 +9645,7 @@ public class TelephonyManager { /** @hide */ @SystemApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public int checkCarrierPrivilegesForPackage(String pkgName) { try { ITelephony telephony = getITelephony(); @@ -9557,6 +9662,7 @@ public class TelephonyManager { /** @hide */ @SystemApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public int checkCarrierPrivilegesForPackageAnyPhone(String pkgName) { try { ITelephony telephony = getITelephony(); @@ -9572,6 +9678,7 @@ public class TelephonyManager { /** @hide */ @SystemApi + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public List<String> getCarrierPackageNamesForIntent(Intent intent) { return getCarrierPackageNamesForIntentAndPhone(intent, getPhoneId()); } @@ -9579,6 +9686,7 @@ public class TelephonyManager { /** @hide */ @SystemApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public List<String> getCarrierPackageNamesForIntentAndPhone(Intent intent, int phoneId) { try { ITelephony telephony = getITelephony(); @@ -9660,6 +9768,7 @@ public class TelephonyManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) @NonNull public List<String> getCarrierPrivilegedPackagesForAllActiveSubscriptions() { try { @@ -9706,6 +9815,7 @@ public class TelephonyManager { * @throws SecurityException if the caller does not have the permission. */ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING) public void setCallComposerStatus(@CallComposerStatus int status) { if (status > CALL_COMPOSER_STATUS_ON || status < CALL_COMPOSER_STATUS_OFF) { @@ -9734,6 +9844,7 @@ public class TelephonyManager { * {@link #CALL_COMPOSER_STATUS_ON} or {@link #CALL_COMPOSER_STATUS_OFF}. */ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING) public @CallComposerStatus int getCallComposerStatus() { try { ITelephony telephony = getITelephony(); @@ -9750,6 +9861,7 @@ public class TelephonyManager { /** @hide */ @SystemApi @SuppressLint("RequiresPermission") + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING) public void dial(String number) { try { ITelephony telephony = getITelephony(); @@ -9882,6 +9994,7 @@ public class TelephonyManager { /** @hide */ @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public boolean supplyPin(String pin) { try { ITelephony telephony = getITelephony(); @@ -9896,6 +10009,7 @@ public class TelephonyManager { /** @hide */ @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public boolean supplyPuk(String puk, String pin) { try { ITelephony telephony = getITelephony(); @@ -9961,6 +10075,7 @@ public class TelephonyManager { @SystemApi @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public PinResult supplyIccLockPin(@NonNull String pin) { try { ITelephony telephony = getITelephony(); @@ -9996,6 +10111,7 @@ public class TelephonyManager { @SystemApi @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public PinResult supplyIccLockPuk(@NonNull String puk, @NonNull String pin) { try { ITelephony telephony = getITelephony(); @@ -10065,6 +10181,7 @@ public class TelephonyManager { * @param handler the {@link Handler} to run the request on. */ @RequiresPermission(android.Manifest.permission.CALL_PHONE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) public void sendUssdRequest(String ussdRequest, final UssdResponseCallback callback, Handler handler) { checkNotNull(callback, "UssdResponseCallback cannot be null."); @@ -10107,6 +10224,7 @@ public class TelephonyManager { * * @return {@code true} if simultaneous voice and data supported, and {@code false} otherwise. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA) public boolean isConcurrentVoiceAndDataSupported() { try { ITelephony telephony = getITelephony(); @@ -10149,6 +10267,7 @@ public class TelephonyManager { /** @hide */ @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) public void toggleRadioOnOff() { try { ITelephony telephony = getITelephony(); @@ -10162,6 +10281,7 @@ public class TelephonyManager { /** @hide */ @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) public boolean setRadio(boolean turnOn) { try { ITelephony telephony = getITelephony(); @@ -10176,6 +10296,7 @@ public class TelephonyManager { /** @hide */ @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) public boolean setRadioPower(boolean turnOn) { try { ITelephony telephony = getITelephony(); @@ -10197,6 +10318,7 @@ public class TelephonyManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) public void shutdownAllRadios() { try { ITelephony telephony = getITelephony(); @@ -10217,6 +10339,7 @@ public class TelephonyManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) public boolean isAnyRadioPoweredOn() { try { ITelephony telephony = getITelephony(); @@ -10263,6 +10386,7 @@ public class TelephonyManager { @SystemApi @RequiresPermission(anyOf = {android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) public @RadioPowerState int getRadioPowerState() { try { ITelephony telephony = getITelephony(); @@ -10289,6 +10413,7 @@ public class TelephonyManager { /** @hide */ @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA) public boolean enableDataConnectivity() { try { ITelephony telephony = getITelephony(); @@ -10303,6 +10428,7 @@ public class TelephonyManager { /** @hide */ @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA) public boolean disableDataConnectivity() { try { ITelephony telephony = getITelephony(); @@ -10316,6 +10442,7 @@ public class TelephonyManager { /** @hide */ @SystemApi + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA) public boolean isDataConnectivityPossible() { try { ITelephony telephony = getITelephony(); @@ -10330,6 +10457,7 @@ public class TelephonyManager { /** @hide */ @SystemApi + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) public boolean needsOtaServiceProvisioning() { try { ITelephony telephony = getITelephony(); @@ -10437,6 +10565,7 @@ public class TelephonyManager { android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.READ_BASIC_PHONE_STATE}) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA) public boolean isDataEnabled() { try { return isDataEnabledForReason(DATA_ENABLED_REASON_USER); @@ -10466,6 +10595,7 @@ public class TelephonyManager { @RequiresPermission(anyOf = {android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.READ_BASIC_PHONE_STATE}) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA) public boolean isDataRoamingEnabled() { boolean isDataRoamingEnabled = false; try { @@ -10503,6 +10633,7 @@ public class TelephonyManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA) public @CdmaRoamingMode int getCdmaRoamingMode() { int mode = CDMA_ROAMING_MODE_RADIO_DEFAULT; try { @@ -10544,6 +10675,7 @@ public class TelephonyManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA) public void setCdmaRoamingMode(@CdmaRoamingMode int mode) { if (getPhoneType() != PHONE_TYPE_CDMA) { throw new IllegalStateException("Phone does not support CDMA."); @@ -10611,6 +10743,7 @@ public class TelephonyManager { */ @SystemApi @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA) public @CdmaSubscription int getCdmaSubscriptionMode() { int mode = CDMA_SUBSCRIPTION_RUIM_SIM; try { @@ -10648,6 +10781,7 @@ public class TelephonyManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA) public void setCdmaSubscriptionMode(@CdmaSubscription int mode) { if (getPhoneType() != PHONE_TYPE_CDMA) { throw new IllegalStateException("Phone does not support CDMA."); @@ -10682,6 +10816,7 @@ public class TelephonyManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA) public void setDataRoamingEnabled(boolean isEnabled) { try { ITelephony telephony = getITelephony(); @@ -10779,6 +10914,7 @@ public class TelephonyManager { * * @return {@code true} if the DTMF tone length can be changed, and {@code false} otherwise. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING) public boolean canChangeDtmfToneLength() { try { ITelephony telephony = getITelephony(); @@ -10842,6 +10978,7 @@ public class TelephonyManager { * * @return {@code true} if the device and carrier both support RTT, {@code false} otherwise. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_IMS) public boolean isRttSupported() { try { ITelephony telephony = getITelephony(); @@ -10861,6 +10998,7 @@ public class TelephonyManager { * @return {@code true} if the device supports hearing aid compatibility, and {@code false} * otherwise. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING) public boolean isHearingAidCompatibilitySupported() { try { ITelephony telephony = getITelephony(); @@ -11208,6 +11346,7 @@ public class TelephonyManager { **/ @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public void setSimPowerState(@SimPowerState int state, @NonNull Executor executor, @NonNull @SetSimPowerStateResult Consumer<Integer> callback) { setSimPowerStateForSlot(getSlotIndex(), state, executor, callback); @@ -11237,6 +11376,7 @@ public class TelephonyManager { **/ @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public void setSimPowerStateForSlot(int slotIndex, @SimPowerState int state, @NonNull Executor executor, @NonNull @SetSimPowerStateResult Consumer<Integer> callback) { @@ -11451,6 +11591,7 @@ public class TelephonyManager { */ @SystemApi @RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING) public @Nullable ComponentName getAndUpdateDefaultRespondViaMessageApplication() { return SmsApplication.getDefaultRespondViaMessageApplication(mContext, true); } @@ -11463,6 +11604,7 @@ public class TelephonyManager { */ @SystemApi @RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING) public @Nullable ComponentName getDefaultRespondViaMessageApplication() { return SmsApplication.getDefaultRespondViaMessageApplication(mContext, false); } @@ -11658,6 +11800,7 @@ public class TelephonyManager { * permission. */ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public int getSubscriptionId(@NonNull PhoneAccountHandle phoneAccountHandle) { int retval = SubscriptionManager.INVALID_SUBSCRIPTION_ID; try { @@ -11724,6 +11867,7 @@ public class TelephonyManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) @Nullable public Locale getSimLocale() { try { final ITelephony telephony = getITelephony(); @@ -11922,6 +12066,7 @@ public class TelephonyManager { Manifest.permission.READ_PHONE_STATE, Manifest.permission.ACCESS_COARSE_LOCATION }) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) public @Nullable ServiceState getServiceState() { return getServiceState(false, false); } @@ -12012,6 +12157,7 @@ public class TelephonyManager { * @return The URI for the ringtone to play when receiving a voicemail from a specific * PhoneAccount. May be {@code null} if no ringtone is set. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING) public @Nullable Uri getVoicemailRingtoneUri(PhoneAccountHandle accountHandle) { try { ITelephony service = getITelephony(); @@ -12039,6 +12185,7 @@ public class TelephonyManager { * @deprecated Use {@link android.provider.Settings#ACTION_CHANNEL_NOTIFICATION_SETTINGS} * instead. */ + @Deprecated public void setVoicemailRingtoneUri(PhoneAccountHandle phoneAccountHandle, Uri uri) { try { ITelephony service = getITelephony(); @@ -12057,6 +12204,7 @@ public class TelephonyManager { * voicemail vibration setting. * @return {@code true} if the vibration is set for this PhoneAccount, {@code false} otherwise. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING) public boolean isVoicemailVibrationEnabled(PhoneAccountHandle accountHandle) { try { ITelephony service = getITelephony(); @@ -12084,6 +12232,7 @@ public class TelephonyManager { * @deprecated Use {@link android.provider.Settings#ACTION_CHANNEL_NOTIFICATION_SETTINGS} * instead. */ + @Deprecated public void setVoicemailVibrationEnabled(PhoneAccountHandle phoneAccountHandle, boolean enabled) { try { @@ -12110,6 +12259,7 @@ public class TelephonyManager { * @return Carrier id of the current subscription. Return {@link #UNKNOWN_CARRIER_ID} if the * subscription is unavailable or the carrier cannot be identified. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public int getSimCarrierId() { try { ITelephony service = getITelephony(); @@ -12134,6 +12284,7 @@ public class TelephonyManager { * @return Carrier name of the current subscription. Return {@code null} if the subscription is * unavailable or the carrier cannot be identified. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public @Nullable CharSequence getSimCarrierIdName() { try { ITelephony service = getITelephony(); @@ -12171,6 +12322,7 @@ public class TelephonyManager { * Return {@link #UNKNOWN_CARRIER_ID} if the subscription is unavailable or the carrier cannot * be identified. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public int getSimSpecificCarrierId() { try { ITelephony service = getITelephony(); @@ -12196,6 +12348,7 @@ public class TelephonyManager { * @return user-facing name of the subscription specific carrier id. Return {@code null} if the * subscription is unavailable or the carrier cannot be identified. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public @Nullable CharSequence getSimSpecificCarrierIdName() { try { ITelephony service = getITelephony(); @@ -12223,6 +12376,7 @@ public class TelephonyManager { * @return matching carrier id from sim MCCMNC. Return {@link #UNKNOWN_CARRIER_ID} if the * subscription is unavailable or the carrier cannot be identified. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public int getCarrierIdFromSimMccMnc() { try { ITelephony service = getITelephony(); @@ -12301,6 +12455,7 @@ public class TelephonyManager { @Nullable @SystemApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public String getAidForAppType(@UiccAppType int appType) { return getAidForAppType(getSubId(), appType); } @@ -12363,6 +12518,7 @@ public class TelephonyManager { * @hide */ @SystemApi + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA) public String getCdmaPrlVersion() { return getCdmaPrlVersion(getSubId()); } @@ -12428,6 +12584,7 @@ public class TelephonyManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CARRIERLOCK) public int setAllowedCarriers(int slotIndex, List<CarrierIdentifier> carriers) { if (carriers == null || !SubscriptionManager.isValidPhoneId(slotIndex)) { return -1; @@ -12554,6 +12711,7 @@ public class TelephonyManager { @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @SetCarrierRestrictionResult + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CARRIERLOCK) public int setCarrierRestrictionRules(@NonNull CarrierRestrictionRules rules) { try { ITelephony service = getITelephony(); @@ -12611,6 +12769,7 @@ public class TelephonyManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CARRIERLOCK) @Nullable public CarrierRestrictionRules getCarrierRestrictionRules() { try { @@ -12670,6 +12829,7 @@ public class TelephonyManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) public void setRadioEnabled(boolean enabled) { try { ITelephony service = getITelephony(); @@ -12791,6 +12951,7 @@ public class TelephonyManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) public void reportDefaultNetworkStatus(boolean report) { try { ITelephony service = getITelephony(); @@ -12816,6 +12977,7 @@ public class TelephonyManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public void resetAllCarrierActions() { try { ITelephony service = getITelephony(); @@ -12935,6 +13097,7 @@ public class TelephonyManager { * @throws IllegalStateException if the Telephony process is not currently available. */ @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA) public void setDataEnabledForReason(@DataEnabledReason int reason, boolean enabled) { setDataEnabledForReason(getSubId(), reason, enabled); } @@ -12981,6 +13144,7 @@ public class TelephonyManager { android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.READ_BASIC_PHONE_STATE }) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA) public boolean isDataEnabledForReason(@DataEnabledReason int reason) { return isDataEnabledForReason(getSubId(), reason); } @@ -13034,6 +13198,7 @@ public class TelephonyManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING) public boolean getEmergencyCallbackMode() { return getEmergencyCallbackMode(getSubId()); } @@ -13072,6 +13237,7 @@ public class TelephonyManager { @SuppressAutoDoc // No support carrier privileges (b/72967236). @RequiresPermission(anyOf = {android.Manifest.permission.READ_PRECISE_PHONE_STATE, android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE}) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) public boolean isManualNetworkSelectionAllowed() { try { ITelephony telephony = getITelephony(); @@ -13092,6 +13258,7 @@ public class TelephonyManager { * @return the most recent cached signal strength info from the modem */ @Nullable + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) public SignalStrength getSignalStrength() { try { ITelephony service = getITelephony(); @@ -13120,6 +13287,7 @@ public class TelephonyManager { android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_BASIC_PHONE_STATE}) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA) public boolean isDataConnectionAllowed() { boolean retVal = false; try { @@ -13140,6 +13308,7 @@ public class TelephonyManager { * data connections over the telephony network. * <p> */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA) public boolean isDataCapable() { if (mContext == null) return true; return mContext.getResources().getBoolean( @@ -13287,6 +13456,7 @@ public class TelephonyManager { */ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @SystemApi + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) public boolean setOpportunisticNetworkState(boolean enable) { String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>"; boolean ret = false; @@ -13315,6 +13485,7 @@ public class TelephonyManager { */ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @SystemApi + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) public boolean isOpportunisticNetworkEnabled() { String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>"; boolean isEnabled = false; @@ -13506,6 +13677,7 @@ public class TelephonyManager { * @throws SecurityException if the caller does not have the required permission */ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) public @NetworkTypeBitMask long getSupportedRadioAccessFamily() { try { ITelephony telephony = getITelephony(); @@ -13541,6 +13713,7 @@ public class TelephonyManager { * @hide */ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING) @SystemApi public void notifyOtaEmergencyNumberDbInstalled() { try { @@ -13567,6 +13740,7 @@ public class TelephonyManager { * @hide */ @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING) @SystemApi public void updateOtaEmergencyNumberDbFilePath( @NonNull ParcelFileDescriptor otaParcelFileDescriptor) { @@ -13592,6 +13766,7 @@ public class TelephonyManager { * @hide */ @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING) @SystemApi public void resetOtaEmergencyNumberDbFilePath() { try { @@ -13651,6 +13826,7 @@ public class TelephonyManager { */ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) @NonNull + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING) public Map<Integer, List<EmergencyNumber>> getEmergencyNumberList() { Map<Integer, List<EmergencyNumber>> emergencyNumberList = new HashMap<>(); try { @@ -13706,6 +13882,7 @@ public class TelephonyManager { */ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) @NonNull + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING) public Map<Integer, List<EmergencyNumber>> getEmergencyNumberList( @EmergencyServiceCategories int categories) { Map<Integer, List<EmergencyNumber>> emergencyNumberListForCategories = new HashMap<>(); @@ -13771,6 +13948,7 @@ public class TelephonyManager { * SIM card(s), Android database, modem, network or defaults; {@code false} otherwise. * @throws IllegalStateException if the Telephony process is not currently available. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING) public boolean isEmergencyNumber(@NonNull String number) { try { ITelephony telephony = getITelephony(); @@ -13810,6 +13988,7 @@ public class TelephonyManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING) public boolean isPotentialEmergencyNumber(@NonNull String number) { try { ITelephony telephony = getITelephony(); @@ -13835,6 +14014,7 @@ public class TelephonyManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING) public int getEmergencyNumberDbVersion() { try { ITelephony telephony = getITelephony(); @@ -13975,6 +14155,7 @@ public class TelephonyManager { * See {@link TelephonyManager.SetOpportunisticSubscriptionResult} * for more details. Pass null if don't care about the result. */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA) public void setPreferredOpportunisticDataSubscription(int subId, boolean needValidation, @Nullable @CallbackExecutor Executor executor, @Nullable Consumer<Integer> callback) { String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>"; @@ -14038,6 +14219,7 @@ public class TelephonyManager { android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE }) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA) public int getPreferredOpportunisticDataSubscription() { String packageName = mContext != null ? mContext.getOpPackageName() : "<unknown>"; String attributionTag = mContext != null ? mContext.getAttributionTag() : null; @@ -14073,6 +14255,7 @@ public class TelephonyManager { * */ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) public void updateAvailableNetworks(@NonNull List<AvailableNetworkInfo> availableNetworks, @Nullable @CallbackExecutor Executor executor, @UpdateAvailableNetworksResult @Nullable Consumer<Integer> callback) { @@ -14223,6 +14406,7 @@ public class TelephonyManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CARRIERLOCK) public void setMultiSimCarrierRestriction(boolean isMultiSimCarrierRestricted) { try { ITelephony service = getITelephony(); @@ -14276,6 +14460,7 @@ public class TelephonyManager { */ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) @IsMultiSimSupportedResult public int isMultiSimSupported() { if (getSupportedModemCount() < 2) { @@ -14306,6 +14491,7 @@ public class TelephonyManager { */ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public void switchMultiSimConfig(int numOfSims) { try { ITelephony telephony = getITelephony(); @@ -14331,6 +14517,7 @@ public class TelephonyManager { * configurations, otherwise return {@code false}. */ @RequiresPermission(Manifest.permission.READ_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public boolean doesSwitchMultiSimConfigTriggerReboot() { try { ITelephony service = getITelephony(); @@ -14383,6 +14570,7 @@ public class TelephonyManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public @CarrierPrivilegeStatus int getCarrierPrivilegeStatus(int uid) { try { ITelephony telephony = getITelephony(); @@ -14496,6 +14684,7 @@ public class TelephonyManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA) public boolean isDataEnabledForApn(@ApnType int apnType) { String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>"; try { @@ -14517,6 +14706,7 @@ public class TelephonyManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA) public boolean isApnMetered(@ApnType int apnType) { try { ITelephony service = getITelephony(); @@ -14545,6 +14735,7 @@ public class TelephonyManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) public void setSystemSelectionChannels(@NonNull List<RadioAccessSpecifier> specifiers, @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) { @@ -14562,6 +14753,7 @@ public class TelephonyManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) public void setSystemSelectionChannels(@NonNull List<RadioAccessSpecifier> specifiers) { Objects.requireNonNull(specifiers, "Specifiers must not be null."); setSystemSelectionChannelsInternal(specifiers, null, null); @@ -14608,6 +14800,7 @@ public class TelephonyManager { */ @SystemApi @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) public @NonNull List<RadioAccessSpecifier> getSystemSelectionChannels() { try { ITelephony service = getITelephony(); @@ -14635,6 +14828,7 @@ public class TelephonyManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public boolean matchesCurrentSimOperator(@NonNull String mccmnc, @MvnoType int mvnoType, @Nullable String mvnoMatchData) { try { @@ -14725,6 +14919,7 @@ public class TelephonyManager { */ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @SystemApi + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING) public void getCallForwarding(@CallForwardingReason int callForwardingReason, @NonNull Executor executor, @NonNull CallForwardingInfoCallback callback) { if (callForwardingReason < CallForwardingInfo.REASON_UNCONDITIONAL @@ -14800,6 +14995,7 @@ public class TelephonyManager { */ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @SystemApi + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING) public void setCallForwarding(@NonNull CallForwardingInfo callForwardingInfo, @Nullable @CallbackExecutor Executor executor, @Nullable @CallForwardingInfoCallback.CallForwardingError @@ -14912,6 +15108,7 @@ public class TelephonyManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING) public void getCallWaitingStatus(@NonNull Executor executor, @NonNull @CallWaitingStatus Consumer<Integer> resultListener) { Objects.requireNonNull(executor); @@ -14960,6 +15157,7 @@ public class TelephonyManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING) public void setCallWaitingEnabled(boolean enabled, @Nullable Executor executor, @Nullable Consumer<Integer> resultListener) { if (resultListener != null) { @@ -15041,6 +15239,7 @@ public class TelephonyManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA) public void setMobileDataPolicyEnabled(@MobileDataPolicy int policy, boolean enabled) { try { ITelephony service = getITelephony(); @@ -15061,6 +15260,7 @@ public class TelephonyManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA) public boolean isMobileDataPolicyEnabled(@MobileDataPolicy int policy) { try { ITelephony service = getITelephony(); @@ -15095,6 +15295,7 @@ public class TelephonyManager { */ @WorkerThread @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) @SystemApi public boolean isIccLockEnabled() { try { @@ -15129,6 +15330,7 @@ public class TelephonyManager { @SystemApi @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public PinResult setIccLockEnabled(boolean enabled, @NonNull String pin) { checkNotNull(pin, "setIccLockEnabled pin can't be null."); try { @@ -15170,6 +15372,7 @@ public class TelephonyManager { @SystemApi @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public PinResult changeIccLockPin(@NonNull String oldPin, @NonNull String newPin) { checkNotNull(oldPin, "changeIccLockPin oldPin can't be null."); checkNotNull(newPin, "changeIccLockPin newPin can't be null."); @@ -15562,6 +15765,7 @@ public class TelephonyManager { * */ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public @NonNull List<String> getEquivalentHomePlmns() { try { ITelephony telephony = getITelephony(); @@ -15675,6 +15879,7 @@ public class TelephonyManager { * @param capability the name of the capability to check for * @return the availability of the capability */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) public boolean isRadioInterfaceCapabilitySupported( @NonNull @RadioInterfaceCapability String capability) { try { @@ -15796,6 +16001,7 @@ public class TelephonyManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) @ThermalMitigationResult public int sendThermalMitigationRequest( @NonNull ThermalMitigationRequest thermalMitigationRequest) { @@ -16067,6 +16273,7 @@ public class TelephonyManager { @WorkerThread @RequiresPermission(anyOf = {android.Manifest.permission.MODIFY_PHONE_STATE, Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION}) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public void bootstrapAuthenticationRequest( @UiccAppTypeExt int appType, @NonNull Uri nafId, @NonNull UaSecurityProtocolIdentifier securityProtocol, @@ -16161,6 +16368,7 @@ public class TelephonyManager { */ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) public void setSignalStrengthUpdateRequest(@NonNull SignalStrengthUpdateRequest request) { Objects.requireNonNull(request, "request must not be null"); @@ -16190,6 +16398,7 @@ public class TelephonyManager { */ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) public void clearSignalStrengthUpdateRequest(@NonNull SignalStrengthUpdateRequest request) { Objects.requireNonNull(request, "request must not be null"); diff --git a/telephony/java/android/telephony/TelephonyScanManager.java b/telephony/java/android/telephony/TelephonyScanManager.java index 122662d3d7c8..e0c529848aae 100644 --- a/telephony/java/android/telephony/TelephonyScanManager.java +++ b/telephony/java/android/telephony/TelephonyScanManager.java @@ -19,6 +19,8 @@ package android.telephony; import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.Nullable; +import android.annotation.RequiresFeature; +import android.content.pm.PackageManager; import android.os.Binder; import android.os.Bundle; import android.os.Handler; @@ -42,6 +44,7 @@ import java.util.concurrent.Executor; /** * Manages the radio access network scan requests and callbacks. */ +@RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) public final class TelephonyScanManager { private static final String TAG = "TelephonyScanManager"; diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java index b0ddf2c28dff..a710e38538ce 100644 --- a/telephony/java/android/telephony/data/ApnSetting.java +++ b/telephony/java/android/telephony/data/ApnSetting.java @@ -1290,8 +1290,8 @@ public class ApnSetting implements Parcelable { && Objects.equals(this.mOperatorNumeric, other.mOperatorNumeric) && Objects.equals(this.mProtocol, other.mProtocol) && Objects.equals(this.mRoamingProtocol, other.mRoamingProtocol) - && xorEqualsInt(this.mMtuV4, other.mMtuV4) - && xorEqualsInt(this.mMtuV6, other.mMtuV6) + && mtuUnsetOrEquals(this.mMtuV4, other.mMtuV4) + && mtuUnsetOrEquals(this.mMtuV6, other.mMtuV6) && Objects.equals(this.mCarrierEnabled, other.mCarrierEnabled) && Objects.equals(this.mNetworkTypeBitmask, other.mNetworkTypeBitmask) && Objects.equals(this.mLingeringNetworkTypeBitmask, @@ -1319,7 +1319,12 @@ public class ApnSetting implements Parcelable { // Equal or one is not specified. private boolean xorEqualsInt(int first, int second) { return first == UNSPECIFIED_INT || second == UNSPECIFIED_INT - || Objects.equals(first, second); + || first == second; + } + + // Equal or one is not specified. Specific to MTU where <= 0 indicates unset. + private boolean mtuUnsetOrEquals(int first, int second) { + return first <= 0 || second <= 0 || first == second; } private String nullToEmpty(String stringValue) { diff --git a/telephony/java/android/telephony/euicc/EuiccCardManager.java b/telephony/java/android/telephony/euicc/EuiccCardManager.java index ab35d77c0b4d..4452d1c88c91 100644 --- a/telephony/java/android/telephony/euicc/EuiccCardManager.java +++ b/telephony/java/android/telephony/euicc/EuiccCardManager.java @@ -19,8 +19,10 @@ import android.annotation.CallbackExecutor; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresFeature; import android.annotation.SystemApi; import android.content.Context; +import android.content.pm.PackageManager; import android.os.Binder; import android.os.RemoteException; import android.service.euicc.EuiccProfileInfo; @@ -61,6 +63,7 @@ import java.util.concurrent.Executor; * @hide */ @SystemApi +@RequiresFeature(PackageManager.FEATURE_TELEPHONY_EUICC) public class EuiccCardManager { private static final String TAG = "EuiccCardManager"; diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java index a1e4f29719d2..a49a61b592ba 100644 --- a/telephony/java/android/telephony/euicc/EuiccManager.java +++ b/telephony/java/android/telephony/euicc/EuiccManager.java @@ -19,6 +19,7 @@ import android.Manifest; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SystemApi; @@ -54,6 +55,7 @@ import java.util.stream.Collectors; * * <p>See {@link #isEnabled} before attempting to use these APIs. */ +@RequiresFeature(PackageManager.FEATURE_TELEPHONY_EUICC) public class EuiccManager { /** diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java index 82d64abd373c..5bae1ad72d93 100644 --- a/telephony/java/android/telephony/ims/ImsMmTelManager.java +++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java @@ -21,11 +21,13 @@ import android.Manifest; import android.annotation.CallbackExecutor; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; import android.annotation.SuppressAutoDoc; import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.content.Context; +import android.content.pm.PackageManager; import android.os.Binder; import android.os.RemoteException; import android.os.ServiceSpecificException; @@ -61,6 +63,7 @@ import java.util.function.Consumer; * Use {@link android.telephony.ims.ImsManager#getImsMmTelManager(int)} to get an instance of this * manager. */ +@RequiresFeature(PackageManager.FEATURE_TELEPHONY_IMS) public class ImsMmTelManager implements RegistrationManager { private static final String TAG = "ImsMmTelManager"; diff --git a/telephony/java/android/telephony/ims/ImsRcsManager.java b/telephony/java/android/telephony/ims/ImsRcsManager.java index 1b047c77d80b..34158685b6d1 100644 --- a/telephony/java/android/telephony/ims/ImsRcsManager.java +++ b/telephony/java/android/telephony/ims/ImsRcsManager.java @@ -19,11 +19,13 @@ package android.telephony.ims; import android.Manifest; import android.annotation.CallbackExecutor; import android.annotation.NonNull; +import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SystemApi; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; @@ -53,6 +55,7 @@ import java.util.function.Consumer; * * Use {@link ImsManager#getImsRcsManager(int)} to create an instance of this manager. */ +@RequiresFeature(PackageManager.FEATURE_TELEPHONY_IMS) public class ImsRcsManager { private static final String TAG = "ImsRcsManager"; diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java index 5aef8a6638ac..677c1a9a7d76 100644 --- a/telephony/java/android/telephony/ims/ProvisioningManager.java +++ b/telephony/java/android/telephony/ims/ProvisioningManager.java @@ -20,6 +20,7 @@ import android.Manifest; import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.StringDef; @@ -55,6 +56,7 @@ import java.util.concurrent.Executor; * applications and may vary. It is up to the carrier and OEM applications to ensure that the * correct provisioning keys are being used when integrating with a vendor's ImsService. */ +@RequiresFeature(PackageManager.FEATURE_TELEPHONY_IMS) public class ProvisioningManager { private static final String TAG = "ProvisioningManager"; diff --git a/telephony/java/android/telephony/ims/RegistrationManager.java b/telephony/java/android/telephony/ims/RegistrationManager.java index a2015cd8f22c..090d4136872e 100644 --- a/telephony/java/android/telephony/ims/RegistrationManager.java +++ b/telephony/java/android/telephony/ims/RegistrationManager.java @@ -21,7 +21,9 @@ import android.annotation.CallbackExecutor; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; +import android.content.pm.PackageManager; import android.net.Uri; import android.os.Binder; import android.os.Bundle; @@ -42,6 +44,7 @@ import java.util.function.Consumer; /** * Manages IMS Service registration state for associated {@link ImsFeature}s. */ +@RequiresFeature(PackageManager.FEATURE_TELEPHONY_IMS) public interface RegistrationManager { /** diff --git a/telephony/java/android/telephony/ims/SipDelegateManager.java b/telephony/java/android/telephony/ims/SipDelegateManager.java index f913df588f40..94e9afbe9e38 100644 --- a/telephony/java/android/telephony/ims/SipDelegateManager.java +++ b/telephony/java/android/telephony/ims/SipDelegateManager.java @@ -21,6 +21,7 @@ import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.content.Context; @@ -57,6 +58,7 @@ import java.util.concurrent.Executor; * @hide */ @SystemApi +@RequiresFeature(PackageManager.FEATURE_TELEPHONY_IMS_SINGLE_REGISTRATION) public class SipDelegateManager { /** diff --git a/tests/ApkVerityTest/AndroidTest.xml b/tests/ApkVerityTest/AndroidTest.xml index 55704eda905e..3c8e1ed99604 100644 --- a/tests/ApkVerityTest/AndroidTest.xml +++ b/tests/ApkVerityTest/AndroidTest.xml @@ -35,6 +35,8 @@ <option name="push" value="ApkVerityTestCert.der->/data/local/tmp/ApkVerityTestCert.der" /> </target_preparer> + <!-- Skip on HWASan. TODO(b/232288278): Re-enable --> + <object type="module_controller" class="com.android.tradefed.testtype.suite.module.SkipHWASanModuleController" /> <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" > <option name="jar" value="ApkVerityTest.jar" /> </test> diff --git a/tools/processors/intdef_mappings/Android.bp b/tools/processors/intdef_mappings/Android.bp index 82a5dac21160..7059c52ddc76 100644 --- a/tools/processors/intdef_mappings/Android.bp +++ b/tools/processors/intdef_mappings/Android.bp @@ -7,27 +7,33 @@ package { default_applicable_licenses: ["frameworks_base_license"], } -java_plugin { - name: "intdef-annotation-processor", - - processor_class: "android.processor.IntDefProcessor", +java_library_host { + name: "libintdef-annotation-processor", srcs: [ ":framework-annotations", "src/**/*.java", - "src/**/*.kt" + "src/**/*.kt", ], use_tools_jar: true, } +java_plugin { + name: "intdef-annotation-processor", + + processor_class: "android.processor.IntDefProcessor", + + static_libs: ["libintdef-annotation-processor"], +} + java_test_host { name: "intdef-annotation-processor-test", srcs: [ "test/**/*.java", - "test/**/*.kt" - ], + "test/**/*.kt", + ], java_resource_dirs: ["test/resources"], static_libs: [ @@ -35,7 +41,7 @@ java_test_host { "truth-prebuilt", "junit", "guava", - "intdef-annotation-processor" + "libintdef-annotation-processor", ], test_suites: ["general-tests"], diff --git a/tools/processors/view_inspector/Android.bp b/tools/processors/view_inspector/Android.bp index ea9974f06a64..877a1d2b5fb3 100644 --- a/tools/processors/view_inspector/Android.bp +++ b/tools/processors/view_inspector/Android.bp @@ -7,10 +7,8 @@ package { default_applicable_licenses: ["frameworks_base_license"], } -java_plugin { - name: "view-inspector-annotation-processor", - - processor_class: "android.processor.view.inspector.PlatformInspectableProcessor", +java_library_host { + name: "libview-inspector-annotation-processor", srcs: ["src/java/**/*.java"], java_resource_dirs: ["src/resources"], @@ -23,6 +21,16 @@ java_plugin { use_tools_jar: true, } +java_plugin { + name: "view-inspector-annotation-processor", + + processor_class: "android.processor.view.inspector.PlatformInspectableProcessor", + + static_libs: [ + "libview-inspector-annotation-processor", + ], +} + java_test_host { name: "view-inspector-annotation-processor-test", @@ -32,7 +40,7 @@ java_test_host { static_libs: [ "junit", "guava", - "view-inspector-annotation-processor" + "libview-inspector-annotation-processor", ], test_suites: ["general-tests"], |