Address all lint issues in androidx.core.os classes, including VFY Relnote: Updated nullability for androidx.core.os classes Fixes: 206113622 Test: MessageCompatTest, LocaleListCompatTest Merged-In: If18cd2bcd8b5de33a5e47997339d32e9a13bc312 Change-Id: If18cd2bcd8b5de33a5e47997339d32e9a13bc312
diff --git a/compose/integration-tests/macrobenchmark-target/src/main/java/androidx/compose/integration/macrobenchmark/target/IoSettingsActivity.kt b/compose/integration-tests/macrobenchmark-target/src/main/java/androidx/compose/integration/macrobenchmark/target/IoSettingsActivity.kt index b652055..17e5427 100644 --- a/compose/integration-tests/macrobenchmark-target/src/main/java/androidx/compose/integration/macrobenchmark/target/IoSettingsActivity.kt +++ b/compose/integration-tests/macrobenchmark-target/src/main/java/androidx/compose/integration/macrobenchmark/target/IoSettingsActivity.kt
@@ -150,7 +150,7 @@ ) { Text( text = stringResource(R.string.io_about_title).uppercase( - LocaleListCompat.getDefault().get(0) + LocaleListCompat.getDefault().get(0)!! ), style = MaterialTheme.typography.body2, fontWeight = FontWeight.SemiBold,
diff --git a/core/core/api/current.txt b/core/core/api/current.txt index 4bed9ff..a8121dd 100644 --- a/core/core/api/current.txt +++ b/core/core/api/current.txt
@@ -1725,12 +1725,12 @@ public final class LocaleListCompat { method public static androidx.core.os.LocaleListCompat create(java.util.Locale!...); method public static androidx.core.os.LocaleListCompat forLanguageTags(String?); - method public java.util.Locale! get(int); + method public java.util.Locale? get(int); method @Size(min=1) public static androidx.core.os.LocaleListCompat getAdjustedDefault(); method @Size(min=1) public static androidx.core.os.LocaleListCompat getDefault(); method public static androidx.core.os.LocaleListCompat getEmptyLocaleList(); method public java.util.Locale? getFirstMatch(String![]); - method @IntRange(from=0xffffffff) public int indexOf(java.util.Locale!); + method @IntRange(from=0xffffffff) public int indexOf(java.util.Locale?); method public boolean isEmpty(); method @IntRange(from=0) public int size(); method public String toLanguageTags();
diff --git a/core/core/api/public_plus_experimental_current.txt b/core/core/api/public_plus_experimental_current.txt index 8554f3b..044adaf 100644 --- a/core/core/api/public_plus_experimental_current.txt +++ b/core/core/api/public_plus_experimental_current.txt
@@ -1730,12 +1730,12 @@ public final class LocaleListCompat { method public static androidx.core.os.LocaleListCompat create(java.util.Locale!...); method public static androidx.core.os.LocaleListCompat forLanguageTags(String?); - method public java.util.Locale! get(int); + method public java.util.Locale? get(int); method @Size(min=1) public static androidx.core.os.LocaleListCompat getAdjustedDefault(); method @Size(min=1) public static androidx.core.os.LocaleListCompat getDefault(); method public static androidx.core.os.LocaleListCompat getEmptyLocaleList(); method public java.util.Locale? getFirstMatch(String![]); - method @IntRange(from=0xffffffff) public int indexOf(java.util.Locale!); + method @IntRange(from=0xffffffff) public int indexOf(java.util.Locale?); method public boolean isEmpty(); method @IntRange(from=0) public int size(); method public String toLanguageTags();
diff --git a/core/core/api/restricted_current.txt b/core/core/api/restricted_current.txt index d008d07..99839e83 100644 --- a/core/core/api/restricted_current.txt +++ b/core/core/api/restricted_current.txt
@@ -2059,12 +2059,12 @@ public final class LocaleListCompat { method public static androidx.core.os.LocaleListCompat create(java.util.Locale!...); method public static androidx.core.os.LocaleListCompat forLanguageTags(String?); - method public java.util.Locale! get(int); + method public java.util.Locale? get(int); method @Size(min=1) public static androidx.core.os.LocaleListCompat getAdjustedDefault(); method @Size(min=1) public static androidx.core.os.LocaleListCompat getDefault(); method public static androidx.core.os.LocaleListCompat getEmptyLocaleList(); method public java.util.Locale? getFirstMatch(String![]); - method @IntRange(from=0xffffffff) public int indexOf(java.util.Locale!); + method @IntRange(from=0xffffffff) public int indexOf(java.util.Locale?); method public boolean isEmpty(); method @IntRange(from=0) public int size(); method public String toLanguageTags();
diff --git a/core/core/src/main/java/androidx/core/os/CancellationSignal.java b/core/core/src/main/java/androidx/core/os/CancellationSignal.java index e1b1fed..80e7c1b0 100644 --- a/core/core/src/main/java/androidx/core/os/CancellationSignal.java +++ b/core/core/src/main/java/androidx/core/os/CancellationSignal.java
@@ -18,7 +18,9 @@ import android.os.Build; +import androidx.annotation.DoNotInline; import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; /** * Static library support version of the framework's {@link android.os.CancellationSignal}. @@ -81,7 +83,7 @@ listener.onCancel(); } if (obj != null && Build.VERSION.SDK_INT >= 16) { - ((android.os.CancellationSignal) obj).cancel(); + Api16Impl.cancel(obj); } } finally { synchronized (this) { @@ -126,7 +128,7 @@ * Gets the framework {@link android.os.CancellationSignal} associated with this object. * <p> * Framework support for cancellation signals was added in - * {@link android.os.Build.VERSION_CODES#JELLY_BEAN} so this method will always + * {@link Build.VERSION_CODES#JELLY_BEAN} so this method will always * return null on older versions of the platform. * </p> * @@ -140,9 +142,9 @@ } synchronized (this) { if (mCancellationSignalObj == null) { - mCancellationSignalObj = new android.os.CancellationSignal(); + mCancellationSignalObj = Api16Impl.createCancellationSignal(); if (mIsCanceled) { - ((android.os.CancellationSignal) mCancellationSignalObj).cancel(); + Api16Impl.cancel(mCancellationSignalObj); } } return mCancellationSignalObj; @@ -154,6 +156,7 @@ try { wait(); } catch (InterruptedException ex) { + // Do nothing } } } @@ -167,4 +170,21 @@ */ void onCancel(); } + + @RequiresApi(16) + static class Api16Impl { + private Api16Impl() { + // This class is not instantiable. + } + + @DoNotInline + static void cancel(Object cancellationSignal) { + ((android.os.CancellationSignal) cancellationSignal).cancel(); + } + + @DoNotInline + static android.os.CancellationSignal createCancellationSignal() { + return new android.os.CancellationSignal(); + } + } }
diff --git a/core/core/src/main/java/androidx/core/os/ConfigurationCompat.java b/core/core/src/main/java/androidx/core/os/ConfigurationCompat.java index e6b4617..ba35171 100644 --- a/core/core/src/main/java/androidx/core/os/ConfigurationCompat.java +++ b/core/core/src/main/java/androidx/core/os/ConfigurationCompat.java
@@ -20,7 +20,9 @@ import android.content.res.Configuration; +import androidx.annotation.DoNotInline; import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; /** * Helper class which allows access to properties of {@link Configuration} in @@ -39,9 +41,21 @@ @NonNull public static LocaleListCompat getLocales(@NonNull Configuration configuration) { if (SDK_INT >= 24) { - return LocaleListCompat.wrap(configuration.getLocales()); + return LocaleListCompat.wrap(Api24Impl.getLocales(configuration)); } else { return LocaleListCompat.create(configuration.locale); } } + + @RequiresApi(24) + static class Api24Impl { + private Api24Impl() { + // This class is not instantiable. + } + + @DoNotInline + static android.os.LocaleList getLocales(Configuration configuration) { + return configuration.getLocales(); + } + } }
diff --git a/core/core/src/main/java/androidx/core/os/EnvironmentCompat.java b/core/core/src/main/java/androidx/core/os/EnvironmentCompat.java index da61db81..78d1f2a 100644 --- a/core/core/src/main/java/androidx/core/os/EnvironmentCompat.java +++ b/core/core/src/main/java/androidx/core/os/EnvironmentCompat.java
@@ -20,7 +20,9 @@ import android.os.Environment; import android.util.Log; +import androidx.annotation.DoNotInline; import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; import java.io.File; import java.io.IOException; @@ -57,9 +59,9 @@ @NonNull public static String getStorageState(@NonNull File path) { if (Build.VERSION.SDK_INT >= 21) { - return Environment.getExternalStorageState(path); + return Api21Impl.getExternalStorageState(path); } else if (Build.VERSION.SDK_INT >= 19) { - return Environment.getStorageState(path); + return Api19Impl.getStorageState(path); } try { @@ -78,5 +80,30 @@ return MEDIA_UNKNOWN; } - private EnvironmentCompat() {} + private EnvironmentCompat() { + } + + @RequiresApi(21) + static class Api21Impl { + private Api21Impl() { + // This class is not instantiable. + } + + @DoNotInline + static String getExternalStorageState(File path) { + return Environment.getExternalStorageState(path); + } + } + + @RequiresApi(19) + static class Api19Impl { + private Api19Impl() { + // This class is not instantiable. + } + + @DoNotInline + static String getStorageState(File path) { + return Environment.getStorageState(path); + } + } }
diff --git a/core/core/src/main/java/androidx/core/os/LocaleListCompat.java b/core/core/src/main/java/androidx/core/os/LocaleListCompat.java index 676b714..a09c8bf 100644 --- a/core/core/src/main/java/androidx/core/os/LocaleListCompat.java +++ b/core/core/src/main/java/androidx/core/os/LocaleListCompat.java
@@ -19,6 +19,7 @@ import android.os.Build; import android.os.LocaleList; +import androidx.annotation.DoNotInline; import androidx.annotation.IntRange; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -33,7 +34,7 @@ public final class LocaleListCompat { private static final LocaleListCompat sEmptyLocaleList = create(); - private LocaleListInterface mImpl; + private final LocaleListInterface mImpl; private LocaleListCompat(LocaleListInterface impl) { mImpl = impl; @@ -71,7 +72,7 @@ @NonNull public static LocaleListCompat create(@NonNull Locale... localeList) { if (Build.VERSION.SDK_INT >= 24) { - return wrap(new LocaleList(localeList)); + return wrap(Api24Impl.createLocaleList(localeList)); } return new LocaleListCompat(new LocaleListCompatWrapper(localeList)); } @@ -82,6 +83,7 @@ * @param index The position to retrieve. * @return The {@link Locale} in the given index */ + @Nullable public Locale get(int index) { return mImpl.get(index); } @@ -113,7 +115,7 @@ * wasn't found */ @IntRange(from = -1) - public int indexOf(Locale locale) { + public int indexOf(@Nullable Locale locale) { return mImpl.indexOf(locale); } @@ -162,7 +164,7 @@ final Locale[] localeArray = new Locale[tags.length]; for (int i = 0; i < localeArray.length; i++) { localeArray[i] = Build.VERSION.SDK_INT >= 21 - ? Locale.forLanguageTag(tags[i]) + ? Api21Impl.forLanguageTag(tags[i]) : forLanguageTagCompat(tags[i]); } return create(localeArray); @@ -203,7 +205,7 @@ @NonNull @Size(min = 1) public static LocaleListCompat getAdjustedDefault() { if (Build.VERSION.SDK_INT >= 24) { - return LocaleListCompat.wrap(LocaleList.getAdjustedDefault()); + return LocaleListCompat.wrap(Api24Impl.getAdjustedDefault()); } else { return LocaleListCompat.create(Locale.getDefault()); } @@ -223,7 +225,7 @@ @NonNull @Size(min = 1) public static LocaleListCompat getDefault() { if (Build.VERSION.SDK_INT >= 24) { - return LocaleListCompat.wrap(LocaleList.getDefault()); + return LocaleListCompat.wrap(Api24Impl.getDefault()); } else { return LocaleListCompat.create(Locale.getDefault()); } @@ -239,8 +241,43 @@ return mImpl.hashCode(); } + @NonNull @Override public String toString() { return mImpl.toString(); } + + @RequiresApi(24) + static class Api24Impl { + private Api24Impl() { + // This class is not instantiable. + } + + @DoNotInline + static LocaleList createLocaleList(Locale... list) { + return new LocaleList(list); + } + + @DoNotInline + static LocaleList getAdjustedDefault() { + return LocaleList.getAdjustedDefault(); + } + + @DoNotInline + static LocaleList getDefault() { + return LocaleList.getDefault(); + } + } + + @RequiresApi(21) + static class Api21Impl { + private Api21Impl() { + // This class is not instantiable. + } + + @DoNotInline + static Locale forLanguageTag(String languageTag) { + return Locale.forLanguageTag(languageTag); + } + } }
diff --git a/core/core/src/main/java/androidx/core/os/LocaleListCompatWrapper.java b/core/core/src/main/java/androidx/core/os/LocaleListCompatWrapper.java index db9306a..94ebde2 100644 --- a/core/core/src/main/java/androidx/core/os/LocaleListCompatWrapper.java +++ b/core/core/src/main/java/androidx/core/os/LocaleListCompatWrapper.java
@@ -18,9 +18,11 @@ import android.os.Build; +import androidx.annotation.DoNotInline; import androidx.annotation.IntRange; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; import androidx.annotation.VisibleForTesting; import java.util.ArrayList; @@ -94,12 +96,13 @@ @Override public int hashCode() { int result = 1; - for (int i = 0; i < mList.length; i++) { - result = 31 * result + mList[i].hashCode(); + for (Locale locale : mList) { + result = 31 * result + locale.hashCode(); } return result; } + @NonNull @Override public String toString() { StringBuilder sb = new StringBuilder(); @@ -125,15 +128,13 @@ mStringRepresentation = ""; } else { final List<Locale> localeList = new ArrayList<>(); - final HashSet<Locale> seenLocales = new HashSet<Locale>(); + final HashSet<Locale> seenLocales = new HashSet<>(); final StringBuilder sb = new StringBuilder(); for (int i = 0; i < list.length; i++) { final Locale l = list[i]; if (l == null) { throw new NullPointerException("list[" + i + "] is null"); - } else if (seenLocales.contains(l)) { - // Ignore repeated locale - } else { + } else if (!seenLocales.contains(l)) { final Locale localeClone = (Locale) l.clone(); localeList.add(localeClone); toLanguageTag(sb, localeClone); @@ -143,7 +144,7 @@ seenLocales.add(localeClone); } } - mList = localeList.toArray(new Locale[localeList.size()]); + mList = localeList.toArray(new Locale[0]); mStringRepresentation = sb.toString(); } } @@ -152,6 +153,8 @@ static void toLanguageTag(StringBuilder builder, Locale locale) { builder.append(locale.getLanguage()); final String country = locale.getCountry(); + // No guarantee that getCountry() was non-null in earlier SDKs. + //noinspection ConstantConditions if (country != null && !country.isEmpty()) { builder.append('-'); builder.append(locale.getCountry()); @@ -160,7 +163,7 @@ private static String getLikelyScript(Locale locale) { if (Build.VERSION.SDK_INT >= 21) { - final String script = locale.getScript(); + final String script = Api21Impl.getScript(locale); if (!script.isEmpty()) { return script; } else { @@ -267,4 +270,16 @@ return computeFirstMatch(Arrays.asList(supportedLocales), false /* assume English is not supported */); } + + @RequiresApi(21) + static class Api21Impl { + private Api21Impl() { + // This class is not instantiable. + } + + @DoNotInline + static String getScript(Locale locale) { + return locale.getScript(); + } + } }
diff --git a/core/core/src/main/java/androidx/core/os/LocaleListPlatformWrapper.java b/core/core/src/main/java/androidx/core/os/LocaleListPlatformWrapper.java index 3968e0f..0d96663 100644 --- a/core/core/src/main/java/androidx/core/os/LocaleListPlatformWrapper.java +++ b/core/core/src/main/java/androidx/core/os/LocaleListPlatformWrapper.java
@@ -28,8 +28,8 @@ final class LocaleListPlatformWrapper implements LocaleListInterface { private final LocaleList mLocaleList; - LocaleListPlatformWrapper(LocaleList localeList) { - mLocaleList = localeList; + LocaleListPlatformWrapper(Object localeList) { + mLocaleList = (LocaleList) localeList; } @Override
diff --git a/core/core/src/main/java/androidx/core/os/MessageCompat.java b/core/core/src/main/java/androidx/core/os/MessageCompat.java index a278c0756..7340ab2 100644 --- a/core/core/src/main/java/androidx/core/os/MessageCompat.java +++ b/core/core/src/main/java/androidx/core/os/MessageCompat.java
@@ -20,8 +20,11 @@ import android.os.Build; import android.os.Looper; import android.os.Message; +import android.view.View; +import androidx.annotation.DoNotInline; import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; /** * Helper for accessing features in {@link Message}. @@ -45,7 +48,7 @@ * Certain operations, such as view invalidation, may introduce synchronization * barriers into the {@link Looper}'s message queue to prevent subsequent messages * from being delivered until some condition is met. In the case of view invalidation, - * messages which are posted after a call to {@link android.view.View#invalidate} + * messages which are posted after a call to {@link View#invalidate} * are suspended by means of a synchronization barrier until the next frame is * ready to be drawn. The synchronization barrier ensures that the invalidation * request is completely handled before resuming. @@ -69,14 +72,14 @@ @SuppressLint("NewApi") public static void setAsynchronous(@NonNull Message message, boolean async) { if (Build.VERSION.SDK_INT >= 22) { - message.setAsynchronous(async); + Api22Impl.setAsynchronous(message, async); return; } if (sTrySetAsynchronous && Build.VERSION.SDK_INT >= 16) { // Since this was an @hide method made public, we can link directly against it with a // try/catch for its absence instead of doing the same dance through reflection. try { - message.setAsynchronous(async); + Api22Impl.setAsynchronous(message, async); } catch (NoSuchMethodError e) { sTrySetAsynchronous = false; } @@ -95,13 +98,13 @@ @SuppressLint("NewApi") public static boolean isAsynchronous(@NonNull Message message) { if (Build.VERSION.SDK_INT >= 22) { - return message.isAsynchronous(); + return Api22Impl.isAsynchronous(message); } if (sTryIsAsynchronous && Build.VERSION.SDK_INT >= 16) { // Since this was an @hide method made public, we can link directly against it with a // try/catch for its absence instead of doing the same dance through reflection. try { - return message.isAsynchronous(); + return Api22Impl.isAsynchronous(message); } catch (NoSuchMethodError e) { sTryIsAsynchronous = false; } @@ -111,4 +114,21 @@ private MessageCompat() { } + + @RequiresApi(22) + static class Api22Impl { + private Api22Impl() { + // This class is not instantiable. + } + + @DoNotInline + static boolean isAsynchronous(Message message) { + return message.isAsynchronous(); + } + + @DoNotInline + static void setAsynchronous(Message message, boolean async) { + message.setAsynchronous(async); + } + } }